home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1994 #2 / Monster Media No. 2 (Monster Media)(1994).ISO / utils1 / 2m21src.zip / 2M-XBIOS.ASM < prev    next >
Assembly Source File  |  1994-05-31  |  125KB  |  3,052 lines

  1.  
  2. ;*********************************************************************
  3. ;*                                                                   *
  4. ;*      2M-XBIOS 1.2  -  (C) Mayo 1994 Ciriaco García de Celis.      *
  5. ;*                                                                   *
  6. ;*          Código para emular al 100% la BIOS AMI de 1993.          *
  7. ;*                         En máquinas PC/XT                         *
  8. ;*                                                                   *
  9. ;*     Si  el  ordenador posee disco duro y una BIOS moderna, la     *
  10. ;*     INT 40h  controla  los  accesos a disquete.  Desviar esta     *
  11. ;*     interrupción  en  lugar  de  la  INT 13h permite que este     *
  12. ;*     programa  tome  el  control  de las disqueteras antes que     *
  13. ;*     cualquier  otro  (incluso  aunque  se  instale después) y     *
  14. ;*     además  permite  seguir trabajando al código del DOS que,     *
  15. ;*     desde  INT 13h,  soluciona  el cruce con las fronteras de     *
  16. ;*     DMA antes de invocar a la INT 40h.                            *
  17. ;*                                                                   *
  18. ;*     Si el ordenador no utilizase la  INT 40h en los accesos a     *
  19. ;*     las disqueteras se desvía INT 13h y se cuelga este código     *
  20. ;*     de la misma, cuidando evitar un cruce con el DMA a través     *
  21. ;*     de un buffer intermedio auxiliar si es preciso.               *
  22. ;*                                                                   *
  23. ;*     Ensamblar con TASM /m5 y linkar con TLINK para obtener un     *
  24. ;*     fichero EXE que se instala con DEVICE desde el CONFIG.SYS     *
  25. ;*                                                                   *
  26. ;*********************************************************************
  27.  
  28. ; ------------ Macros de propósito general.
  29.  
  30. XPUSH          MACRO regmem            ; apilar lista de registros
  31.                  IRP rm, <regmem>
  32.                    PUSH rm
  33.                  ENDM
  34.                ENDM
  35.  
  36. XPOP           MACRO regmem            ; desapilar lista de registros
  37.                  IRP rm, <regmem>
  38.                    POP rm
  39.                  ENDM
  40.                ENDM
  41.  
  42. XPUSHA         MACRO
  43.                  XPUSH <AX, BX, CX, DX, SI, DI>
  44.                ENDM
  45.  
  46. XPOPA          MACRO
  47.                  XPOP  <DI, SI, DX, CX, BX, AX>
  48.                ENDM
  49.  
  50. XSHL           MACRO regmem, cuenta
  51.                  REPT cuenta
  52.                    SHL regmem,1
  53.                  ENDM
  54.                ENDM
  55.  
  56. XSHR           MACRO regmem, cuenta
  57.                  REPT cuenta
  58.                    SHR regmem,1
  59.                  ENDM
  60.                ENDM
  61.  
  62. XROR           MACRO regmem, cuenta
  63.                  REPT cuenta
  64.                    ROR regmem,1
  65.                  ENDM
  66.                ENDM
  67.  
  68. XROL           MACRO regmem, cuenta
  69.                  REPT cuenta
  70.                    ROL regmem,1
  71.                  ENDM
  72.                ENDM
  73.  
  74. ; ************ Inicio del área residente.
  75.  
  76. _PRINCIPAL     SEGMENT
  77.                ASSUME CS:_PRINCIPAL, DS:_PRINCIPAL
  78.  
  79.                ORG   0
  80.  
  81. ini_residente  EQU   $
  82.  
  83.                DD    -1           ; encadenamiento con otros drivers
  84. tipo_drive     DW    8000h        ; palabra de atributo:
  85.                                   ; bit 15 a 1: dispositivo caracteres
  86.                                   ; bit 14 a 0: sin control IOCTL
  87.                DW    estrategia   ; rutina de estrategia
  88.                DW    interrupcion ; rutina de interrupción
  89.                DB    "2M-BIOS$"   ; nombre del dispositivo
  90.  
  91. estrategia     PROC  FAR
  92.                MOV   CS:pcab_pet_segm,ES
  93.                MOV   CS:pcab_pet_desp,BX
  94.                RET
  95. estrategia     ENDP
  96.  
  97. interrupcion   PROC  FAR
  98.                CALL  main  ; tras instalar: XPUSH <DS, BX> y MOV BX,??
  99. pcab_pet_segm  DW    ?
  100.                MOV   DS,BX
  101.                DB    0BBh  ; opcode de MOV BX,??
  102. pcab_pet_desp  DW    ?
  103.                MOV   WORD PTR [BX+3],8103h  ; código de error
  104.                XPOP  <BX, DS>
  105.                RET
  106. interrupcion   ENDP
  107.  
  108. ; ****************************************
  109. ; *                                      *
  110. ; *   D A T O S    R E S I D E N T E S   *
  111. ; *                                      *
  112. ; ****************************************
  113.  
  114. ; ------------ Identificación estandarizada del programa.
  115.  
  116. program_id     LABEL BYTE
  117. segmento_real  DW    0   ; segmento real donde será cargado
  118. offset_real    DW    0   ; offset real     "     "     "
  119. longitud_total DW    0   ; zona de memoria ocupada (párrafos)
  120. info_extra     DB    03h ; bits 0, 1 y 2-> 000: normal, con PSP
  121.                          ;                 001: bloque UMB XMS
  122.                          ;                 010: *.SYS
  123.                          ;                 011: *.SYS formato EXE
  124.                          ; bit 7 a 1: «extension_id» definida
  125. multiplex_id   DB    0   ; número Multiplex de este TSR
  126. vectores_id    DW    tabla_vectores
  127. extension_id   DW    0
  128.                DB    "*##*"
  129. autor_nom_ver  DB    "CiriSOFT:2M-XBIOS:1.2",0
  130.  
  131.                DB    3  ; número de vectores de interrupción usados
  132. tabla_vectores EQU   $
  133.                DB    15h           ; INT 15h
  134. ant_int15      LABEL DWORD         ; dirección original
  135. ant_int15_off  DW    0
  136. ant_int15_seg  DW    0
  137.                DB    2Fh           ; INT 2Fh
  138. ant_int2F      LABEL DWORD         ; dirección original
  139. ant_int2F_off  DW    0
  140. ant_int2F_seg  DW    0
  141.                DB    40h           ; INT 40h
  142. ant_int40      LABEL DWORD         ; dirección original
  143. ant_int40_off  DW    0
  144. ant_int40_seg  DW    0
  145.                DB    13h           ; INT 13h podría llegar a usarse
  146. ant_int13      LABEL DWORD
  147. ant_int13_off  DW    0
  148. ant_int13_seg  DW    0
  149.  
  150. ; ***************************************
  151. ; *                                     *
  152. ; *   C O D I G O   R E S I D E N T E   *
  153. ; *                                     *
  154. ; ***************************************
  155.  
  156. ; ------------ Rutina de gestión de INT 2Fh.
  157.  
  158. ges_int2F      PROC  FAR
  159.                STI
  160.                CMP   AH,CS:multiplex_id
  161.                JE    preguntan
  162.                JMP   CS:ant_int2F      ; saltar al gestor de INT 2Fh
  163. preguntan:     CMP   DI,1992h
  164.                JNE   ret_no_info       ; no llama alguien del convenio
  165.                MOV   AX,ES
  166.                CMP   AX,1492h
  167.                JNE   ret_no_info       ; no llama alguien del convenio
  168.                PUSH  CS
  169.                POP   ES                ; sí llama: darle información
  170.                LEA   DI,autor_nom_ver
  171. ret_no_info:   MOV   AX,0FFFFh         ; "entrada multiplex en uso"
  172.                IRET
  173. ges_int2F      ENDP
  174.  
  175. ; ------------ Rutina de gestión de INT 15h.
  176.  
  177. ges_int15      PROC  FAR
  178.                STI
  179.                CMP   AX,90FDh
  180.                JE    ret_clc
  181.                CMP   AX,9001h
  182.                JE    ret_clc
  183.                JMP   CS:ant_int15
  184. ret_clc:       CLC
  185.                RET   2
  186. ges_int15      ENDP
  187.  
  188. ; ------------ Rutina de control de INT 40h.
  189.  
  190. r_flags        EQU   WORD PTR [BP+18h] ; constantes para parámetros
  191. r_flags_l      EQU   BYTE PTR [BP+18h]
  192. r_flags_h      EQU   BYTE PTR [BP+19h]
  193. r_ax           EQU   WORD PTR [BP+12h]
  194. r_al           EQU   BYTE PTR [BP+12h]
  195. r_ah           EQU   BYTE PTR [BP+13h]
  196. r_cx           EQU   WORD PTR [BP+10h]
  197. r_cl           EQU   BYTE PTR [BP+10h]
  198. r_ch           EQU   BYTE PTR [BP+11h]
  199. r_dx           EQU   WORD PTR [BP+0Eh]
  200. r_dl           EQU   BYTE PTR [BP+0Eh]
  201. r_dh           EQU   BYTE PTR [BP+0Fh]
  202. r_bx           EQU   WORD PTR [BP+0Ch]
  203. r_bl           EQU   BYTE PTR [BP+0Ch]
  204. r_bh           EQU   BYTE PTR [BP+0Dh]
  205. r_bp           EQU   WORD PTR [BP+0Ah]
  206. r_si           EQU   WORD PTR [BP+08h]
  207. r_di           EQU   WORD PTR [BP+06h]
  208. r_ds           EQU   WORD PTR [BP+04h]
  209. r_es           EQU   WORD PTR [BP+02h]
  210.  
  211. ges_int40      PROC
  212.                STI
  213.                CLD
  214.                PUSH  AX
  215.                PUSH  CX
  216.                PUSH  DX
  217.                PUSH  BX
  218.                PUSH  BP
  219.                PUSH  SI
  220.                PUSH  DI
  221.                PUSH  DS
  222.                PUSH  ES
  223.                PUSH  BP
  224.                MOV   BP,SP
  225.                PUSH  AX
  226.                MOV   AX,40h
  227.                MOV   DS,AX
  228.                POP   AX
  229.                PUSH  AX
  230.                MOV   AL,AH
  231.                CMP   AL,18h
  232.                JA    mal_funcion
  233.                CMP   AL,5
  234.                JBE   func_oper
  235.                CMP   AL,8
  236.                JNE   func_aux?
  237.                MOV   AL,6
  238.                JMP   func_oper
  239. func_aux?:     CMP   AL,15h
  240.                JB    mal_funcion
  241.                SUB   AL,0Eh
  242. func_oper:     CBW
  243.                MOV   DI,AX
  244.                POP   AX
  245.                SHL   DI,1
  246.                JMP   CS:tab_jmp[DI]    ; ejecutar función
  247. main_exit:     MOV   AL,AH             ; preservar resultado
  248.                LAHF                    ; preservar flags
  249.                PUSH  AX
  250.                PUSH  AX
  251.                MOV   AX,40h
  252.                MOV   DS,AX
  253.                POP   AX
  254.                MOV   AL,r_dl           ; DL a la llamada (unidad)
  255.                CMP   AL,1
  256.                JA    u_det             ; unidad incorrecta
  257.                XOR   AH,AH
  258.                MOV   BX,90h
  259.                ADD   BX,AX             ; [BX] -> estado físico unidad
  260.                TEST  BYTE PTR DS:[BX],10h  ; ¿densidad determinada?
  261.                JZ    u_det                 ; no
  262.                MOV   DL,4                  ; sí
  263.                MUL   DL
  264.                MOV   CL,AL                 
  265.                SHL   DL,CL
  266.                OR    DS:[8Fh],DL           ; unidad determinada
  267. u_det:         POP   AX
  268.                SAHF                    ; recuperar flags
  269.                MOV   AH,AL             ; recuperar resultado
  270. exit_i40:      MOV   r_ah,AH           ; AH para la salida del IRET
  271.                MOV   AX,201H           ; STI + STC en flags
  272.                JC    set_err           ; hay error
  273.                AND   r_flags_l,0FEH    ; CLC (si no hay error)
  274.                DEC   AX                ; dejar sólo STI
  275. set_err:       OR    r_flags,AX        ; flags a la salida del IRET
  276.                POP   BP
  277.                POP   ES
  278.                POP   DS
  279.                POP   DI
  280.                POP   SI
  281.                POP   BP
  282.                POP   BX
  283.                POP   DX
  284.                POP   CX
  285.                POP   AX                ; registros con resultado
  286.                IRET
  287. ges_int40      ENDP
  288.  
  289. mal_funcion:   POP   AX
  290.                MOV   AH,1              ; función/parámetro incorrecto
  291.                MOV   DS:[41h],AH       ; código de error
  292.                STC                     ; condición de error
  293.                JMP   exit_i40
  294.  
  295. ; ------------ Función 0: Resetear el sistema de disco.
  296.  
  297. reset          PROC
  298.                CALL  full_init         ; inicialización plena
  299.                MOV   DS:[41h],AH       ; código de error
  300.                MOV   AL,AH             ; preservar código
  301.                LAHF                    ; preservar flags
  302.                PUSH  AX
  303.                PUSH  DS
  304.                XOR   SI,SI
  305.                MOV   DS,SI
  306.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  307.                MOV   CL,[SI+2]
  308.                POP   DS
  309.                MOV   DS:[40h],CL       ; tics para detención motor
  310.                POP   AX
  311.                SAHF
  312.                MOV   AH,AL             ; restaurado código y flags
  313.                JMP   exit_i40
  314. reset          ENDP
  315.  
  316. ; ------------ Inicialización plena.
  317.  
  318. full_init      PROC
  319.                AND   BYTE PTR DS:[3Eh],0F0h   ; futuro recalibramiento
  320.                JMP   init_fdc                 ; inicializar FDC
  321. fdc_init:      JC    init_end
  322.                JMP   send_specify             ; enviar specify
  323. specify_sent:  JC    init_end
  324.                XOR   AH,AH                    ; no hay error
  325. init_end:      RET
  326. full_init      ENDP
  327.  
  328. ; ------------ Función 1: Obtener resultado de la última operación.
  329.  
  330. get_status     PROC
  331.                MOV   AH,DS:[41h]
  332.                OR    AH,AH
  333.                JZ    no_err
  334.                STC
  335. no_err:        JMP   exit_i40
  336. get_status     ENDP
  337.  
  338. ; ------------ Función 15h: Obtener el tipo de disco.
  339.  
  340. get_disk_type  PROC
  341.                CMP   DL,1
  342.                JBE   gdt_ok
  343.                MOV   AH,1              ; función/parámetro incorrecto
  344.                STC
  345.                MOV   DS:[41h],AH       ; código de error
  346.                JMP   gdt_exit
  347. gdt_ok:        MOV   BX,90h
  348.                XOR   DH,DH
  349.                ADD   BX,DX             ; [BX] -> estado físico unidad
  350.                MOV   BL,[BX]           ; estado físico de la unidad
  351.                OR    BL,BL
  352.                JNZ   gdt_posible
  353.                XOR   AH,AH             ; no existe tal unidad
  354.                JMP   gdt_bye
  355. gdt_posible:   AND   BL,7
  356.                JZ    gdt_without       ; 360K
  357.                CMP   BL,3
  358.                JE    gdt_without       ; 360K
  359.                MOV   AH,2
  360.                JMP   gdt_bye           ; con soporte cambio de línea
  361. gdt_without:   MOV   AH,1              ; sin soporte cambio de línea
  362. gdt_bye:       CLC
  363.                MOV   BYTE PTR DS:[41h],0  ; siempre sin error
  364. gdt_exit:      JMP   main_exit
  365. get_disk_type  ENDP
  366.  
  367. ; ------------ Función 17h: Establecer tipo de soporte para formateo.
  368.  
  369. set_type_fmt   PROC
  370.                XOR   AH,AH
  371.                CMP   DL,1
  372.                JBE   set_tp
  373. set_tp_bad_p:  MOV   AH,1              ; función/parámetro incorrecto
  374. set_tp_err:    MOV   DS:[41h],AH       ; código de error
  375.                STC
  376.                JMP   set_tp_exit
  377. set_tp:        CMP   AL,0              ; validar parámetro
  378.                JE    set_tp_bad_p
  379.                CMP   AL,4
  380.                JA    set_tp_bad_p
  381.                MOV   BX,90h
  382.                XOR   DH,DH
  383.                ADD   BX,DX             ; [BX] -> estado físico unidad
  384.                CMP   AL,1              ; ¿360K en 360K?
  385.                JNE   set_tp_n360
  386.                MOV   BYTE PTR DS:[BX],93h  ; actualizar variable tipo
  387.                MOV   BYTE PTR DS:[41h],0   ; anular errores previos
  388.                JMP   set_tp_t_exit
  389. set_tp_n360:   MOV   CX,AX
  390.                PUSH  BX
  391.                CALL  motor_on              ; arrancar motor
  392.                POP   SI
  393.                PUSH  SI
  394.                CALL  read_disk_chg         ; ¿cambio de disco?
  395.                POP   BX
  396.                CMP   AH,6                  ; (0: no, 6: sí)
  397.                JBE   set_tp_cd             ; haya cambio o no
  398.                CMP   AH,80h
  399.                JNE   set_tp_cd             ; sí existe disco
  400.                CMP   BYTE PTR DS:[BX],97h  ; ¿250 Kbps y no es 5.25?
  401.                JE    set_tp_err            ; error
  402.                MOV   BYTE PTR DS:[BX],61h  ; 300 Kbps, try 360 en 1.2
  403.                JMP   set_tp_err            ; error
  404. set_tp_cd:     CMP   CL,4                  ; ¿720K en 720K?
  405.                JNE   set_tp_n720           ; no
  406.                MOV   BYTE PTR DS:[BX],97h  ; actualizar variable tipo
  407.                JMP   set_tp_t_exit
  408. set_tp_n720:   CMP   CL,2                  ; ¿360K en 1.2M?
  409.                JNE   set_tp_ndd            ; no
  410.                MOV   BYTE PTR DS:[BX],74h  ; actualizar variable tipo
  411.                JMP   set_tp_t_exit
  412. set_tp_ndd:    MOV   BYTE PTR DS:[BX],15h  ; 1.2M en 1.2M
  413. set_tp_t_exit: OR    AH,AH                 ; comprobar posible error
  414.                JNZ   set_tp_err
  415.                MOV   BYTE PTR DS:[41h],0
  416. set_tp_exit:   JMP   main_exit
  417. set_type_fmt   ENDP
  418.  
  419. ; ------------ Función 16h: Detectar cambio de disco.
  420.  
  421. detect_change  PROC
  422.                CMP   DL,1
  423.                JBE   det_ch
  424.                MOV   AH,1              ; función/parámetro incorrecto
  425. det_ch_r_err:  STC
  426.                JMP   det_ch_end
  427. det_ch:        XOR   DH,DH
  428.                MOV   BX,90h
  429.                ADD   BX,DX               ; [BX] -> estado físico
  430.                CMP   BYTE PTR DS:[BX],0  ; ¿estado indeterminado?...
  431.                MOV   AH,80h              ; "unidad no preparada"
  432.                JE    det_ch_r_err        ; ...en efecto
  433.                MOV   AH,[BX]
  434.                AND   AH,7
  435.                JZ    det_ch_yes          ; 360K en 360K, no es posible
  436.                CMP   AH,3
  437.                JNE   det_ch_calc         ; no es 360K en 360K
  438. det_ch_yes:    MOV   AH,6                ; hay cambio (o desconocido)
  439.                STC
  440.                JMP   det_ch_end
  441. det_ch_calc:   CALL  motor_on          ; arrancar motor
  442.                MOV   DX,3F7h
  443.                IN    AL,DX             ; leer línea de cambio de disco
  444.                SHL   AL,1
  445.                JC    det_ch_yes        ; hay cambio de disco
  446.                XOR   AH,AH             ; no lo hay
  447. det_ch_end:    MOV   DS:[41h],AH       ; actualizar código de error
  448.                PUSH  AX
  449.                PUSH  SI
  450.                PUSH  DS
  451.                MOV   SI,0
  452.                MOV   DS,SI
  453.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  454.                MOV   AL,[SI+2]
  455.                POP   DS
  456.                MOV   DS:[40h],AL       ; tiempo detención motor
  457.                POP   SI
  458.                POP   AX
  459.                JMP   main_exit
  460. detect_change  ENDP
  461.  
  462. ; ------------ Funciones 2, 3 y 4: Leer, escribir y verificar.
  463.  
  464. read_wr_verify PROC
  465.                CMP   DL,1
  466.                JBE   rwv_posible
  467.                MOV   AH,1              ; función/parámetro incorrecto
  468. rwv_err:       MOV   DS:[41h],AH       ; código de error
  469.                XOR   AL,AL
  470.                STC
  471.                JMP   rwv_exit
  472. rwv_posible:   MOV   SI,90h
  473.                PUSH  DX
  474.                XOR   DH,DH
  475.                ADD   SI,DX               ; [SI] -> estado físico
  476.                CMP   BYTE PTR DS:[SI],0  ; ¿estado indeterminado?...
  477.                POP   DX
  478.                JNE   rwv_state_ok      ; no
  479.                PUSH  AX
  480.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  481.                JZ    rwv_type_ok       ; ha resultado posible
  482.                POP   AX
  483. rwv_not_ready: MOV   AH,80h            ; "unidad no preparada"
  484.                JMP   rwv_err
  485. rwv_type_ok:   OR    AL,AL             ; ¿existe la unidad?
  486.                POP   AX
  487.                JZ    rwv_not_ready     ; no existe esa unidad
  488.                MOV   BYTE PTR DS:[SI],2    ; probando 1.2M en 1.2M
  489. rwv_state_ok:  MOV   DI,3Fh
  490.                AND   BYTE PTR DS:[DI],7Fh  ; operación Read/Verify
  491.                CMP   AH,3                  ; ¿operación de escritura?
  492.                JNE   rwv_nowr
  493.                OR    BYTE PTR DS:[DI],80h  ; operación Write/Format
  494. rwv_nowr:      PUSH  SI
  495.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  496.                JNZ   rwv_media_ok
  497.                CMP   AL,1
  498.                JE    rwv_set360            ; es de 360K
  499.                CMP   AL,3
  500.                JNE   rwv_media_ok          ; no es de 720K
  501.                MOV   BYTE PTR DS:[SI],97h    ; forzar medio de 720K
  502.                JMP   rwv_media_ok
  503. rwv_set360:    MOV   BYTE PTR DS:[SI],93h    ; forzar medio de 360K
  504. rwv_media_ok:  CALL  motor_on          ; arrancar motores
  505.                CALL  read_disk_chg     ; leer línea de cambio de disco
  506.                POP   SI
  507.                JNC   rwv_no_dschg      ; no hay cambio de disco
  508. rwv_end_err:   CALL  end_io_access
  509.                JMP   rwv_err
  510. rwv_no_dschg:  TEST  BYTE PTR DS:[SI],10h  ; ¿densidad determinada?
  511.                JNZ   rwv_set_rate          ; en efecto
  512.                CALL  detect_media          ; pues determinarla
  513.                JC    rwv_end_err           ; problemas
  514.                JMP   rwv_dens_ok
  515. rwv_set_rate:  CALL  select_rate       ; seleccionar la velocidad
  516. rwv_dens_ok:   MOV   SI,90h
  517.                PUSH  DX
  518.                XOR   DH,DH
  519.                ADD   SI,DX             ; [SI] -> estado físico unidad
  520.                POP   DX
  521.                MOV   AX,0AF03H                ; AF byte 0 specify 2.88
  522.                CMP   BYTE PTR DS:[SI],0D7h    ; ¿2.88M?
  523.                JE    rwv_spec_ok              ; así es
  524.                MOV   AX,0DF03h                ; DF para 360/1.2/720
  525.                CMP   BYTE PTR DS:[SI],17h     ; ¿1.44M?
  526.                JNE   rwv_spec_ok              ; no
  527.                MOV   AH,0BFh                  ; sí
  528. rwv_spec_ok:   MOV   SI,AX                    ; SI 0-7: orden specify
  529.                MOV   DI,2                     ; DI 0-7: byte 1 specify
  530.                MOV   CH,3                     ; comando de 3 bytes
  531.                OR    BYTE PTR DS:[3Eh],80h    ; no esperar INT
  532.                CALL  exec_cmd
  533.                JC    rwv_end_err       ; fallo
  534.                MOV   AX,r_ax
  535.                XOR   AH,AH
  536.                PUSH  DS
  537.                XOR   SI,SI
  538.                MOV   DS,SI
  539.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  540.                MOV   CL,r_AL
  541.                ADD   CL,r_CL           ; [*] último sector a acceder
  542.                MOV   [SI+4],CL
  543.                MOV   CL,[SI+3]         ; bytes/sector
  544.                SHL   AL,CL             ; multiplicar por nº sectores
  545.                MOV   CL,80h
  546.                MUL   CL                ; y por 128
  547.                POP   DS
  548.                DEC   AX                ; un byte menos...
  549.                MOV   CX,AX             ; ...cuenta para el DMA
  550.                CALL  eval_dir_DMA
  551.                JNC   rwv_dma_ok        ; no hay problemas con el DMA
  552.                MOV   CX,r_cx           ; restaurar CX
  553.                JMP   rwv_end_err       ; problemas con el DMA
  554. rwv_dma_ok:    MOV   AX,r_ax
  555.                CMP   AH,2              ; ¿operación de lectura?
  556.                JNE   rwv_no_read
  557.                MOV   AH,46h            ; byte de modo DMA para lectura
  558.                JMP   rwv_dma_set
  559. rwv_no_read:   CMP   AH,3              ; ¿escritura?
  560.                MOV   AH,4Ah            ; modo DMA para escritura
  561.                JZ    rwv_dma_set
  562.                MOV   AH,42h            ; modo DMA para verificación
  563. rwv_dma_set:   CALL  set_dma           ; preparar DMA
  564.                MOV   AX,r_ax
  565.                MOV   CX,r_cx           ; restaurar parámetros
  566.                JMP   perform_io        ; efectuar E/S
  567. io_performed:  CALL  end_io_access
  568.                OR    AL,AL
  569.                JZ    rwv_end
  570.                SUB   BL,CL             ; próximo sector-sector inicial
  571.                MOV   AL,BL             ; nº sectores transferidos
  572. rwv_end:       MOV   AH,DS:[41h]
  573.                OR    AH,AH             ; ¿error?
  574.                JZ    rwv_exit
  575.                STC                     ; señalizar error
  576. rwv_exit:      MOV   r_al,AL           ; nº sectores transferidos
  577.                JMP   main_exit
  578. read_wr_verify ENDP
  579.  
  580. ; ------------ Función 5: Formatear pista.
  581.  
  582. format_track   PROC
  583.                CMP   DL,1
  584.                JBE   fmt_do
  585.                MOV   AH,1              ; función/parámetro incorrecto
  586. fmt_exit_err:  MOV   DS:[41h],AH       ; código de error
  587.                STC
  588.                JMP   main_exit
  589. fmt_do:        MOV   SI,90h
  590.                PUSH  DX
  591.                XOR   DH,DH
  592.                ADD   SI,DX             ; [SI] -> estado físico unidad
  593.                POP   DX
  594.                CMP   BYTE PTR DS:[SI],0
  595.                MOV   AH,80h            ; "unidad no preparada"
  596.                JE    fmt_exit_err      ; indeterminado
  597.                MOV   DI,3Fh
  598.                OR    BYTE PTR DS:[DI],80h  ; no esperar INT
  599.                CALL  motor_on          ; arrancar motores
  600.                CALL  read_disk_chg     ; leer línea de cambio de disco
  601.                JNC   fmt_posible       ; no hay cambio de disco
  602. fmt_err:       CALL  end_io_access
  603.                JMP   fmt_exit_err      ; error
  604. fmt_posible:   CALL  select_rate       ; seleccionar la velocidad
  605.                CALL  send_specify      ; enviar comando specify
  606.                PUSH  DS
  607.                XOR   SI,SI
  608.                MOV   DS,SI
  609.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  610.                MOV   AL,r_AL
  611.                MOV   [SI+4],AL         ; [*] sectores por pista
  612.                POP   DS
  613.                XOR   AH,AH
  614.                MOV   CL,4
  615.                MUL   CL                ; 4 bytes para cada uno
  616.                MOV   CX,AX
  617.                DEC   CX                ; un byte menos...
  618.                CALL  eval_dir_DMA      ; ...cuenta para el DMA
  619.                JC    fmt_err           ; cruza frontera de DMA
  620.                MOV   AH,4Ah            ; modo DMA para escritura
  621.                CALL  set_dma           ; preparar DMA
  622.                MOV   CX,r_cx           ; restaurar CX
  623.                CALL  seek              ; llevar el cabezal a la pista
  624.                JNC   fmt_continue      ; no hay problemas
  625. fmt_err_res:   MOV   BX,42h
  626.                MOV   CX,7
  627.                PUSH  AX
  628.                CALL  get_results       ; leer bytes de resultados
  629.                POP   AX
  630.                JMP   fmt_exit          ; error
  631. fmt_continue:  XSHL  DH,2
  632.                OR    DH,DL             ; DH = byte 1 del comando
  633.                MOV   DL,0CDh           ; comando de formateo del FDC
  634.                PUSH  DS
  635.                XOR   SI,SI
  636.                MOV   DS,SI
  637.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  638.                PUSH  AX
  639.                MOV   AX,[SI+7]         ; GAP formateo/byte de relleno
  640.                MOV   [BP],AX           ; preservarlo
  641.                POP   AX
  642.                MOV   DI,[SI+3]         ; bytes/sector, sectores/pista
  643.                POP   DS
  644.                MOV   SI,DX             ; primeros bytes del comando
  645.                MOV   CH,6              ; comando de 6 bytes
  646.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  647.                CALL  exec_cmd
  648.                JC    fmt_err_res       ; hay error
  649.                MOV   BX,42h
  650.                MOV   CX,7
  651.                CALL  get_results       ; leer bytes de resultados
  652.                JC    fmt_exit
  653.                CALL  get_bios_err      ; obtener código de error
  654. fmt_exit:      MOV   DS:[41h],AH       ; código de error
  655.                CALL  end_io_access
  656.                MOV   AH,DS:[41h]
  657.                OR    AH,AH
  658.                JZ    fmt_end           ; no hay error
  659.                STC
  660. fmt_end:       JMP   main_exit
  661. format_track   ENDP
  662.  
  663. ; ------------ Función 8: Obtener parámetros de disco.
  664.  
  665. get_drv_param  PROC
  666.                CMP   DL,80h
  667.                JB    gdrv_do
  668.                MOV   AH,1              ; función/parámetro incorrecto
  669.                MOV   DS:[41h],AH       ; código de error
  670.                STC
  671.                JMP   main_exit
  672. gdrv_do:       XOR   DI,DI
  673.                XOR   SI,SI
  674.                XOR   DH,DH
  675.                MOV   AL,DS:[10h]       ; hardware instalado
  676.                AND   AL,0C1h           ; nº disqueteras (7-6) y bit
  677.                MOV   DI,2              ; que indica arrancable (0)
  678.                CMP   AL,41h            ; ¿dos disqueteras? (DI=2)
  679.                JE    gdrv_ndisk_ok     ; en efecto
  680.                DEC   DI
  681.                CMP   AL,1              ; ¿una disquetera? (DI=1)
  682.                JE    gdrv_ndisk_ok     ; así es
  683.                JMP   gdrv_res_null     ; no hay disqueteras
  684. gdrv_ndisk_ok: CMP   DL,1
  685.                JBE   gdrv_a_or_b       ; la disquetera es A: o B:
  686.                JMP   gdrv_half_res
  687. gdrv_a_or_b:   CALL  peek_cmos         ; leer tipo de disqueteras
  688.                OR    DL,DL
  689.                JNZ   gdrv_sel
  690.                MOV   CL,4
  691.                SHR   AL,CL             ; dejar disquetera en bits 0-3
  692. gdrv_sel:      AND   AL,0Fh
  693.                JZ    gdrv_media?       ; no existe esa unidad
  694.                CMP   AL,5
  695.                JA    gdrv_media?       ; es mayor de 2.88M
  696.                XOR   AH,AH
  697.                MOV   SI,AX
  698.                MOV   DH,AL
  699.                MOV   BX,90h
  700.                ADD   BL,DL             ; [BX] -> estado físico unidad
  701.                MOV   AL,[BX]
  702.                TEST  AL,10h            ; ¿densidad determinada?
  703.                JNZ   gdrv_calc_p       ; en efecto
  704.                CMP   SI,1              ; ¿unidad de 360K?
  705.                MOV   AL,93h            ; 360K en 360K, 250 Kbps
  706.                JE    gdrv_media_ok
  707.                CMP   SI,2              ; ¿unidad de 1.2M?
  708.                MOV   AL,2              ; "intentando 1.2M"
  709.                JE    gdrv_media_ok
  710.                CMP   SI,3              ; ¿unidad de 720K?
  711.                MOV   AL,97h            ; 720K en 720K, 250 Kbps
  712.                JE    gdrv_media_ok
  713.                CMP   SI,4              ; ¿unidad de 1.44M?
  714.                MOV   AL,7              ; "intentando 1.44M"
  715.                JE    gdrv_media_ok
  716.                MOV   AL,0C7h           ; 2.88M en 2.88M
  717. gdrv_media_ok: MOV   [BX],AL
  718.                JMP   gdrv_calc_p       ; medio físico asignado
  719. gdrv_media?:   MOV   BX,90h
  720.                ADD   BL,DL             ; [BX] -> estado físico unidad
  721.                MOV   AL,[BX]
  722.                TEST  AL,10h            ; ¿densidad determinada?
  723.                JZ    gdrv_eval         ; no
  724.                MOV   AH,AL
  725.                AND   AL,0C0h           ; aislar bits de velocidad
  726.                CMP   AL,80h            ; ¿250 Kbps?
  727.                MOV   SI,2              ; 1.2M
  728.                JNE   gdrv_m144?
  729.                TEST  AH,4
  730.                MOV   SI,1              ; 360K
  731.                JZ    gdrv_calc_p
  732.                MOV   SI,4              ; 1.44M
  733. gdrv_m144?:    TEST  AH,7
  734.                JZ    gdrv_calc_p
  735.                MOV   SI,4              ; 1.44M
  736. gdrv_calc_p:   MOV   BX,DI
  737.                MOV   DI,SI
  738.                DEC   DI
  739.                ADD   DI,DI
  740.                MOV   AX,CS:tab_disksize[DI] ; AL sect/pista, AH pistas
  741.                MOV   r_dh,1                 ; dos cabezales
  742.                MOV   DI,CS:tab_ptr_1e[DI]   ; DI -> tabla parámetros
  743.                PUSH  CS
  744.                POP   ES                ; ES:DI -> parámetros disco
  745. gdrv_set_res:  MOV   r_dl,BL           ; número de unidades
  746.                MOV   r_ch,AH           ; mayor número de cilindro
  747.                MOV   r_cl,AL           ; mayor número de sector
  748.                MOV   r_bl,DH           ; tipo de la unidad
  749.                MOV   r_bh,0
  750.                MOV   r_es,ES           ; ES:DI para la salida
  751.                MOV   r_di,DI
  752.                XOR   AX,AX
  753.                MOV   DS:[41h],AH       ; resultado correcto
  754.                MOV   r_al,AL
  755.                JMP   main_exit
  756. gdrv_res_null: XOR   DI,DI             ; devolver todo a 0
  757. gdrv_half_res: XOR   DH,DH
  758.                XOR   AX,AX
  759.                MOV   ES,AX
  760.                MOV   r_dh,0
  761.                MOV   BX,DI
  762.                XOR   DI,DI
  763.                JMP   gdrv_set_res      ; resultado trivial
  764. gdrv_eval:     MOV   BX,DI
  765.                OR    SI,SI
  766.                JZ    gdrv_res_null     ; no existe la unidad
  767.                CMP   SI,3
  768.                JBE   gdrv_calc_p       ; es de 5¼
  769.                XOR   SI,SI
  770.                JMP   gdrv_res_null
  771. get_drv_param  ENDP
  772.  
  773. ; ------------ Función 18h: Establecer densidad de formateo.
  774.  
  775. set_media_fmt  PROC
  776.                CMP   DL,1
  777.                JBE   setm_do
  778.                MOV   AH,1              ; función/parámetro incorrecto
  779. setm_exit_err: STC
  780.                JMP   main_exit
  781. setm_do:       CALL  get_drive_type    ; obtener tipo disquetera en AL
  782.                JZ    setm_drv_ok
  783. setm_drv_unkn: MOV   AH,0Ch            ; tipo de unidad desconocido
  784.                JMP   setm_exit_err
  785. setm_drv_ok:   XOR   AH,AH
  786.                MOV   DI,AX             ; tipo de unidad
  787.                MOV   DL,r_dl
  788.                MOV   BX,90h
  789.                XOR   DH,DH
  790.                ADD   BX,DX             ; [BX] -> estado físico unidad
  791.                CMP   AL,1              ; ¿360K?
  792.                JNE   setm_not360
  793.                MOV   CX,r_cx           ; restaurar CX
  794.                CMP   CX,2709h          ; ¿40 pistas 9 sectores?
  795.                LEA   SI,t360in360
  796.                JNZ   setm_drv_unkn     ; sólo se permite ese formato
  797.                JMP   setm_360in360
  798. setm_not360:   CMP   AL,3              ; ¿720K?
  799.                JNE   setm_not720
  800.                MOV   CX,r_cx           ; restaurar CX
  801.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  802.                JNE   setm_drv_unkn     ; sólo se permite ese formato
  803.                JMP   setm_setm
  804. setm_not720:   CMP   AL,4              ; ¿1.44M?
  805.                JE    setm_1440
  806.                CMP   AL,2              ; ¿1.2M?
  807.                JE    setm_1200
  808.                CMP   AL,5              ; ¿2.88M?
  809.                JNE   setm_drv_unkn
  810.                MOV   CX,r_cx           ; 2.88M: restaurar CX
  811.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  812.                JE    setm_setm         ; correcto
  813.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  814.                JE    setm_setm         ; correcto
  815.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  816.                JE    setm_setm         ; correcto
  817.                JMP   setm_drv_unkn     ; permitir sólo esos formatos
  818. setm_1200:     MOV   CX,r_cx           ; restaurar CX
  819.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  820.                JE    setm_setm         ; correcto
  821.                CMP   CX,2709h          ; ¿80 pistas 9 sectores?
  822.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  823.                JMP   setm_setm         ; correcto
  824. setm_1440:     MOV   CX,r_cx           ; restaurar CX
  825.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  826.                JE    setm_setm         ; correcto
  827.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  828.                JNE   setm_drv_unkn     ; permitir sólo esos formatos
  829. setm_setm:     MOV   CX,r_cx           ; restaurar CX
  830.                CMP   CX,4F12h          ; ¿80 pistas 18 sectores?
  831.                MOV   AL,17h            ; su byte de medio físico
  832.                LEA   SI,t1440          ; es 1.44M
  833.                MOV   DH,0              ; 500 Kbps
  834.                JZ    setm_m_ok
  835.                CMP   CX,4F09h          ; ¿80 pistas 9 sectores?
  836.                MOV   AL,97h            ; su byte de medio físico
  837.                LEA   SI,t720           ; es 720K
  838.                MOV   DH,2              ; 250 Kbps
  839.                JZ    setm_m_ok
  840.                CMP   CX,4F0Fh          ; ¿80 pistas 15 sectores?
  841.                MOV   AL,15h            ; su byte de medio físico
  842.                LEA   SI,t1200          ; es 1.2M
  843.                MOV   DH,0              ; 500 Kbps
  844.                JZ    setm_m_ok
  845.                CMP   CX,4F24h          ; ¿80 pistas 36 sectores?
  846.                MOV   AL,0D7h           ; su byte de medio físico
  847.                LEA   SI,t2880          ; es 2.88M
  848.                MOV   DH,3              ; 1 Mbps
  849.                JZ    setm_m_ok
  850.                MOV   AL,74h            ; byte medio físico 360K en 1.2
  851.                LEA   SI,t360en1200     ; es 360K en 1.2M
  852.                MOV   DH,1              ; 300 Kbps
  853. setm_m_ok:     MOV   [BX],AL           ; establecer medio físico
  854.                PUSH  DX
  855.                CALL  set_rate          ; velocidad de transferencia DH
  856.                POP   DX
  857.                MOV   AL,[BX]
  858.                AND   AL,0C0h
  859.                AND   BYTE PTR DS:[8Bh],3Fh  ; borrar bits de velocidad
  860.                OR    BYTE PTR DS:[8Bh],AL   ; nueva velocidad
  861.                MOV   r_di,SI
  862.                MOV   r_es,CS              ; retornar tabla parámetros
  863.                MOV   BYTE PTR DS:[41h],0  ; no hay error
  864.                XOR   AH,AH
  865.                JMP   main_exit
  866. setm_360in360: MOV   DH,2                 ; 250 Kbps
  867.                MOV   AL,93h               ; 360K en 360K
  868.                JMP   setm_m_ok
  869. set_media_fmt  ENDP
  870.  
  871. ; ------------ Recalibrar.
  872.  
  873. recalibrate    PROC
  874.                PUSH  SI
  875.                PUSH  CX
  876.                PUSH  DX
  877.                MOV   DH,DL
  878.                MOV   DL,7              ; comando "recalibrate"
  879.                MOV   SI,DX
  880.                MOV   CH,2              ; comando de 2 bytes
  881.                AND   BYTE PTR DS:[3Eh],7Fh  ; con espera de IRQ
  882.                CALL  exec_cmd
  883.                JC    recal_end         ; fallo
  884.                MOV   SI,8              ; "leer estado interrupciones"
  885.                MOV   CH,1              ; comando de 1 byte
  886.                OR    BYTE PTR DS:[3Eh],80h  ; sin espera de IRQ
  887.                CALL  exec_cmd
  888.                JC    recal_end         ; fallo
  889.                MOV   BX,42h
  890.                MOV   CX,2              ; 2 bytes de resultado
  891.                CALL  get_results       ; almacenar resultado
  892.                JC    recal_end         ; fallo
  893.                MOV   BX,42h
  894.                MOV   AH,40h
  895.                MOV   DL,[BX]           ; ST0
  896.                AND   DL,60h
  897.                CMP   DL,60h            ; ¿terminación anormal y
  898.                STC                     ; seek-end?
  899.                JE    recal_end         ; fallo
  900.                POP   DX
  901.                PUSH  DX
  902.                XOR   DH,DH             
  903.                MOV   BX,94H
  904.                ADD   BX,DX
  905.                MOV   BYTE PTR DS:[BX],0  ; cilindro en curso = 0
  906.                MOV   CL,DL
  907.                MOV   DL,1
  908.                SHL   DL,CL
  909.                OR    DS:[3Eh],DL       ; unidad recalibrada
  910.                MOV   CX,1
  911.                CALL  retardo           ; retardo de 1 ms
  912.                XOR   AH,AH
  913. recal_end:     MOV   DS:[41h],AH       ; código de error / acierto
  914.                POP   DX
  915.                POP   CX
  916.                POP   SI
  917.                RET
  918. recalibrate    ENDP
  919.  
  920. ; ------------ Llevar el cabezal al cilindro adecuado.
  921.  
  922. seek           PROC
  923.                PUSH  BX
  924.                PUSH  CX
  925.                MOV   AH,DS:[3Eh]       ; estado de recalibración
  926.                MOV   CL,DL
  927.                INC   CL
  928.                SHR   AH,CL
  929.                JC    seek_only
  930.                CALL  recalibrate       ; hay que recalibrar
  931.                JNC   seek_only
  932.                CALL  recalibrate       ; segundo intento
  933.                JNC   seek_only
  934.                JMP   seek_exit
  935. seek_only:     MOV   BX,94H
  936.                XOR   DH,DH
  937.                ADD   BX,DX             ; [BX] -> cilindro actual
  938.                MOV   SI,90h
  939.                ADD   SI,DX             ; [SI] -> estado físico unidad
  940.                MOV   DL,CH
  941.                TEST  BYTE PTR DS:[SI],20h  ; ¿hacer double stepping?
  942.                JZ    seek_cil_ok1
  943.                ADD   DL,DL             ; sí: cilindro=cilindro*2
  944. seek_cil_ok1:  CMP   [BX],DL           ; ¿ya estamos en ese cilindro?
  945.                MOV   DX,r_dx
  946.                JNE   seek_do           ; aún no
  947.                CMP   BYTE PTR DS:[41h],40h  ; ¿hubo "seek error"?
  948.                JE    seek_do
  949.                XOR   AH,AH             ; no, seek innecesario
  950.                JMP   seek_exit
  951. seek_do:       XSHL  DH,2
  952.                OR    DH,DL             ; byte 1 del comando seek
  953.                MOV   DL,0FH            ; orden seek
  954.                MOV   SI,DX
  955.                MOV   CL,CH             ; cilindro
  956.                MOV   DX,r_dx           ; unidad / cabezal
  957.                MOV   BX,90h
  958.                XOR   DH,DH
  959.                ADD   BX,DX                 ; [BX] -> estado físico
  960.                TEST  BYTE PTR DS:[BX],20h  ; ¿hacer double stepping?
  961.                JZ    seek_cil_ok2      ; no
  962.                ADD   CL,CL             ; sí: cilindro=cilindro*2
  963. seek_cil_ok2:  MOV   DI,CX
  964.                MOV   CH,3              ; comando de 3 bytes
  965.                AND   BYTE PTR DS:[3Eh],7Fh  ; hay que esperar IRQ
  966.                CALL  exec_cmd
  967.                JNC   seek_ok           ; seek correcto
  968.                JMP   seek_result
  969. seek_ok:       MOV   SI,8              ; "leer estado interrupciones"
  970.                MOV   CH,1              ; comando de 1 byte
  971.                OR    BYTE PTR DS:[3Eh],80h  ; no hay que esperar IRQ
  972.                CALL  exec_cmd
  973.                JC    seek_result       ; fallo
  974.                MOV   BX,42h
  975.                MOV   CX,2
  976.                CALL  get_results       ; leer bytes de resultados
  977.                JC    seek_result
  978.                MOV   BX,42h
  979.                MOV   AH,40h            ; "seek error"
  980.                MOV   DL,[BX]           ; ST0
  981.                AND   DL,60h
  982.                CMP   DL,60h            ; comprobarlo
  983.                STC
  984.                JE    seek_result       ; terminación brusca
  985.                MOV   DX,r_dx           ; restaurar DX
  986.                POP   CX
  987.                PUSH  CX                ; restaurar CX
  988.                MOV   SI,94H
  989.                XOR   DH,DH
  990.                ADD   SI,DX
  991.                MOV   [SI],CH           ; actualizar cilindro actual
  992.                MOV   BX,90h
  993.                ADD   BX,DX             ; [BX] -> estado físico unidad
  994.                MOV   BL,[BX]
  995.                TEST  BL,20h            ; ¿double stepping?
  996.                JZ    seek_cil_ok3
  997.                ADD   [SI],CH           ; pues cilindro*2
  998. seek_cil_ok3:  PUSH  DS
  999.                XOR   SI,SI
  1000.                MOV   DS,SI
  1001.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1002.                MOV   AL,[SI+9]         ; tiempo estabilización cabezal
  1003.                POP   DS
  1004.                TEST  BYTE PTR DS:[3Fh],80h  ; ¿operación en curso?
  1005.                JZ    seek_wait         ; es lectura o verificación
  1006.                OR    AL,AL
  1007.                JNZ   seek_wait         ; escritura, cte != 0
  1008.                CMP   BL,17h
  1009.                MOV   AL,0Fh
  1010.                JE    seek_wait         ; 15 ms excepto para 360K
  1011.                AND   BL,7
  1012.                MOV   AL,14h
  1013.                JZ    seek_wait         ; 20 ms para unidades de 360K
  1014.                CMP   BL,3
  1015.                JE    seek_wait         ; 20 ms para unidades de 360K
  1016.                MOV   AL,0Fh            ; 15 ms para demás unidades
  1017. seek_wait:     OR    AL,AL
  1018.                JZ    seek_wait_end
  1019.                MOV   CX,1
  1020.                CALL  retardo           ; esperar 1 ms...
  1021.                DEC   AL
  1022.                JMP   seek_wait         ; ...durante AL veces
  1023. seek_wait_end: XOR   AH,AH
  1024. seek_result:   MOV   DS:[41h],AH       ; resultado
  1025. seek_exit:     MOV   DX,r_dx           ; restaurar DX
  1026.                POP   CX
  1027.                POP   BX
  1028.                RET
  1029. seek           ENDP
  1030.  
  1031. ; ------------ Ejecutar operación de E/S a través del FDC.
  1032.  
  1033. perform_io     PROC
  1034.                CALL  seek
  1035.                JNC   p_io
  1036. p_io_dsk_err:  MOV   AL,0              ; fallo
  1037.                PUSH  AX
  1038.                MOV   BX,42h
  1039.                MOV   CX,7
  1040.                CALL  get_results       ; leer bytes de resultados
  1041.                POP   AX
  1042.                JMP   p_io_exit
  1043. p_io:          PUSH  DS                ; preparar bytes comando R/W
  1044.                XOR   SI,SI
  1045.                MOV   DS,SI
  1046.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1047.                MOV   AX,[SI+2]
  1048.                AND   AX,0FF00h         ; AH = bytes por sector
  1049.                MOV   AL,CL             ; AL = primer sector
  1050.                MOV   [BP],AX
  1051.                MOV   BX,[SI+4]         ; BL=sectores/pista, BH=GAP R/W
  1052.                MOV   CL,[SI+6]         ; CL=longitud de sector (tam=0)
  1053.                POP   DS
  1054.                MOV   SI,90h
  1055.                XOR   DH,DH
  1056.                ADD   SI,DX             ; nº sector/tamaño (bytes 4-5)
  1057.                MOV   DL,[SI]           ; estado físico de la unidad
  1058.                AND   DL,7
  1059.                MOV   DH,1Bh            ; GAP R/W para 1.2M/1.44M/2.88M
  1060.                CMP   DL,5
  1061.                JE    p_io_gap_ok       ; 1.2M en 1.2M
  1062.                CMP   BYTE PTR DS:[SI],17h
  1063.                JE    p_io_gap_ok            ; 1.44M
  1064.                CMP   BYTE PTR DS:[SI],0D7h
  1065.                JE    p_io_gap_ok            ; 2.88M
  1066.                MOV   DH,23h            ; GAP R/W para 360K en 1.2M
  1067.                CMP   DL,4
  1068.                JE    p_io_gap_ok       ; 360K en 1.2M
  1069.                MOV   DH,2Ah            ; GAP R/W para demás casos
  1070. p_io_gap_ok:   MOV   BH,DH             ; BX=numsect/GAP (bytes 6-7)
  1071.                MOV   DX,r_dx           ; restaurar DX
  1072.                PUSH  CX
  1073.                MOV   CL,CH             ; cilindro
  1074.                MOV   CH,DH             ; cabezal
  1075.                MOV   DI,CX             ; cabezal/cilindro (bytes 2-3)
  1076.                XSHL  DH,2
  1077.                OR    DH,DL             ; byte 1 de comando FDC
  1078.                MOV   DL,0E6h           ; comando leer datos
  1079.                MOV   AX,r_ax           ; orden
  1080.                CMP   AH,3              ; ¿write?
  1081.                JNE   p_io_orden_ok
  1082.                MOV   DL,0C5h           ; comando escribir datos
  1083. p_io_orden_ok: MOV   SI,DX             ; (bytes 0-1 de la orden)
  1084.                POP   CX
  1085.                MOV   CH,9
  1086.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1087.                CALL  exec_cmd
  1088.                JNC   p_io_dsk_ok
  1089.                JMP   p_io_dsk_err      ; fallo
  1090. p_io_dsk_ok:   MOV   BX,42h
  1091.                MOV   CX,7
  1092.                CALL  get_results       ; leer bytes de resultados
  1093.                JNC   p_io_res_ok
  1094.                MOV   AL,0
  1095.                JMP   p_io_exit         ; fallo: respetar código error
  1096. p_io_res_ok:   CALL  get_bios_err
  1097. p_io_exit:     MOV   DS:[41h],AH
  1098.                MOV   DX,r_dx           ; restaurar registros
  1099.                MOV   BX,r_bx
  1100.                MOV   CX,r_cx
  1101.                JMP   io_performed      ; continuar operación E/S
  1102. perform_io     ENDP
  1103.  
  1104. ; ------------ Arrancar motor si no lo está.
  1105.  
  1106. motor_on       PROC
  1107.                PUSH  DX
  1108.                PUSH  CX
  1109.                CLI                     ; * evitar reentrada
  1110.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1111.                AND   BYTE PTR DS:[3Fh],0CFh  ; a 0 bits de disquetera
  1112.                MOV   CH,DL
  1113.                XSHL  DL,4
  1114.                OR    DS:[3Fh],DL       ; nueva disquetera seleccionada
  1115.                MOV   CL,CH
  1116.                MOV   DL,DS:[3Fh]       ; estado de motores
  1117.                INC   CL
  1118.                SHR   DL,CL
  1119.                JC    motor_is_on       ; motor ya en marcha
  1120.                MOV   DL,1
  1121.                DEC   CL
  1122.                SHL   DL,CL
  1123.                OR    DS:[3Fh],DL       ; señalizar que está en marcha
  1124.                STI                     ; * fin de la fase crítica
  1125.                MOV   AL,DS:[3Fh]       ; estado de motores
  1126.                XROR  AL,4
  1127.                OR    AL,0CH            ; no resetear, modo DMA
  1128.                MOV   DX,3F2h
  1129.                OUT   DX,AL             ; registro salida digital
  1130.                MOV   AX,90FDh
  1131.                INT   15h               ; permitir multitarea
  1132.                JC    motor_on_end
  1133.                MOV   AH,DS:[3Fh]
  1134.                PUSH  DS
  1135.                PUSH  SI
  1136.                XOR   SI,SI
  1137.                MOV   DS,SI
  1138.                LDS   SI,DWORD PTR DS:[78h]  ; DS:SI -> INT 1Eh
  1139.                MOV   AL,[SI+0Ah]
  1140.                POP   SI                ; AL = tiempo aceleración motor
  1141.                POP   DS                ;      en octavos de segundo
  1142.                SHL   AH,1
  1143.                JNC   motor_on_rv       ; operación read/verify
  1144.                CMP   AL,8
  1145.                JAE   motor_on_wait
  1146.                MOV   AL,8
  1147.                JMP   motor_on_wait     ; escritura: al menos 1 segundo
  1148. motor_on_rv:   CMP   AL,5
  1149.                JAE   motor_on_wait
  1150.                MOV   AL,5              ; read/verify: al menos 625 ms
  1151. motor_on_wait: MOV   CX,125
  1152.                CALL  retardo           ; retardo de unos 125 ms
  1153.                DEC   AL
  1154.                JNZ   motor_on_wait     ; completar retardo
  1155.                JMP   motor_on_end
  1156. motor_is_on:   STI
  1157.                MOV   AL,DS:[3Fh]       ; estado de motores
  1158.                XROR  AL,4
  1159.                OR    AL,0CH            ; no resetear, modo DMA
  1160.                MOV   DX,3F2h
  1161.                OUT   DX,AL             ; seleccionar unidad
  1162. motor_on_end:  POP   CX
  1163.                POP   DX
  1164.                RET
  1165. motor_on       ENDP
  1166.  
  1167. ; ------------ Asignar cuenta para detención motor y devolver en BL
  1168. ;              y AL el próximo número de sector a transferir.
  1169.  
  1170. end_io_access  PROC
  1171.                PUSH  AX
  1172.                PUSH  DS
  1173.                XOR   BX,BX
  1174.                MOV   DS,BX
  1175.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1176.                MOV   AH,[BX+2]         ; tics hasta detención motor
  1177.                MOV   AL,[BX+4]
  1178.                INC   AL                ; sectores/pista + 1
  1179.                POP   DS
  1180.                MOV   BX,42h
  1181.                CMP   CH,[BX+3]         ; ¿mismo cilindro resultante?
  1182.                JNE   end_io_exit
  1183.                CMP   DH,[BX+4]         ; ¿mismo cabezal resultante?
  1184.                JNE   end_io_exit
  1185.                MOV   AL,[BX+5]         ; número de sector resultante
  1186. end_io_exit:   MOV   DS:[40h],AH       ; tiempo para detención motor
  1187.                MOV   BL,AL             ; último nº sector transferido
  1188.                POP   AX
  1189.                RET
  1190. end_io_access  ENDP
  1191.  
  1192. ; ------------ Leer la línea de cambio de disco y bajarla si está
  1193. ;              activa.
  1194.  
  1195. read_disk_chg  PROC
  1196.                PUSH  CX
  1197.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1198.                MOV   AH,0
  1199.                JNZ   fallo_cmos
  1200.                DEC   AL
  1201.                JZ    rdchg_set_cod     ; evitar test en 360K
  1202. fallo_cmos:    MOV   AL,[SI]           ; estado físico de la unidad
  1203.                AND   AL,7
  1204.                JZ    rdchg_set_cod     ; evitar test en 360K
  1205.                CMP   AL,3
  1206.                JE    rdchg_set_cod     ; evitar test en 360K
  1207.                MOV   DX,3F7h           ; registro de entrada digital
  1208.                IN    AL,DX             ; leer línea de cambio de disco
  1209.                SHL   AL,1
  1210.                JNC   rdchg_exit        ; no hay cambio de disco
  1211.                AND   BYTE PTR DS:[SI],0EFH  ; medio no determinado
  1212.                CALL  full_init         ; inicialización plena
  1213.                JC    rdchg_exit        ; fallo
  1214.                MOV   DX,r_dx           ; restaurar DX
  1215.                MOV   CH,1
  1216.                CALL  seek              ; cabezal a cilindro 1
  1217.                JC    rdchg_exit
  1218.                MOV   CH,0
  1219.                CALL  seek              ; cabezal a cilindro 0
  1220.                JC    rdchg_exit
  1221.                MOV   AH,6              ; error "disk changed"
  1222.                MOV   DX,3F7h
  1223.                IN    AL,DX             ; leer línea de cambio de disco
  1224.                SHL   AL,1
  1225.                JNC   rdchg_set_cod     ; se ha podido bajar
  1226.                MOV   AH,80h            ; no se pudo: no hay disquete
  1227. rdchg_set_cod: OR    AH,AH
  1228.                JZ    rdchg_exit
  1229.                STC
  1230. rdchg_exit:    MOV   DX,r_dx           ; restaurar DX
  1231.                POP   CX
  1232.                RET
  1233. read_disk_chg  ENDP
  1234.  
  1235. ; ------------ Programar el DMA para efectuar la E/S.
  1236.  
  1237. set_dma        PROC
  1238.                PUSH  AX
  1239.                PUSH  DX
  1240.                CLI
  1241.                MOV   AL,AH
  1242.                OUT   0CH,AL            ; clear first/last flip-flop
  1243.                JCXZ  $+2               ; retardo para E/S
  1244.                JCXZ  $+2
  1245.                OUT   0BH,AL            ; registro de modo del DMA
  1246.                JCXZ  $+2
  1247.                JCXZ  $+2
  1248.                MOV   AL,CL
  1249.                OUT   5,AL
  1250.                JCXZ  $+2
  1251.                JCXZ  $+2
  1252.                MOV   AL,CH
  1253.                OUT   5,AL              ; enviada cuenta de bytes
  1254.                JCXZ  $+2
  1255.                JCXZ  $+2
  1256.                MOV   AL,BL
  1257.                OUT   4,AL
  1258.                JCXZ  $+2
  1259.                JCXZ  $+2
  1260.                MOV   AL,BH
  1261.                OUT   4,AL              ; enviada dirección base
  1262.                JCXZ  $+2
  1263.                JCXZ  $+2
  1264.                MOV   AX,ES
  1265.                OUT   81H,AL            ; registro de página canal 2
  1266.                JCXZ  $+2
  1267.                JCXZ  $+2
  1268.                MOV   AL,2
  1269.                OUT   0AH,AL            ; habilitar canal 2 del DMA
  1270.                STI
  1271.                POP   DX
  1272.                POP   AX
  1273.                RET
  1274. set_dma        ENDP
  1275.  
  1276. ; ------------ Calcular parámetros para programar el DMA.
  1277.  
  1278. eval_dir_DMA   PROC
  1279.                PUSH  CX
  1280.                XOR   AX,AX
  1281.                MOV   CX,ES             ; segmento ES
  1282.                SHL   CX,1              ; desplazar...
  1283.                RCL   AL,1
  1284.                SHL   CX,1
  1285.                RCL   AL,1
  1286.                SHL   CX,1
  1287.                RCL   AL,1
  1288.                SHL   CX,1
  1289.                RCL   AL,1              ; ... AL:CX >> 4
  1290.                MOV   BX,r_bx           ; offset BX
  1291.                ADD   BX,CX
  1292.                ADC   AX,0              ; AX:BX dirección física 20 bit
  1293.                MOV   ES,AX             ; página de DMA
  1294.                POP   CX
  1295.                MOV   AX,CX
  1296.                ADD   AX,BX
  1297.                JNC   eval_dma_ret      ; no cruza frontera de 64k
  1298.                MOV   AH,9              ; "DMA across 64k boundary"
  1299. eval_dma_ret:  RET
  1300. eval_dir_DMA   ENDP
  1301.  
  1302. ; ------------ Enviar comando completo al FDC de CH bytes, contenido
  1303. ;              en SI, DI, [BP], BX y CL (parte baja - alta).
  1304.  
  1305. send_full_cmd  PROC
  1306.                MOV   AX,SI
  1307.                MOV   AH,AL
  1308.                CALL  fdc_write         ; enviar SI-L
  1309.                DEC   CH
  1310.                JBE   send_full_ret     ; acabado (ZF=1) ó error (CF=1)
  1311.                MOV   AX,SI
  1312.                CALL  fdc_write         ; enviar SI-H
  1313.                DEC   CH
  1314.                JBE   send_full_ret
  1315.                MOV   AX,DI
  1316.                MOV   AH,AL
  1317.                CALL  fdc_write         ; enviar DI-L
  1318.                DEC   CH
  1319.                JBE   send_full_ret
  1320.                MOV   AX,DI
  1321.                CALL  fdc_write         ; enviar DI-H
  1322.                DEC   CH
  1323.                JBE   send_full_ret
  1324.                MOV   AX,[BP]
  1325.                MOV   AH,AL
  1326.                CALL  fdc_write         ; enviar [BP]-L
  1327.                DEC   CH
  1328.                JBE   send_full_ret
  1329.                MOV   AX,[BP]
  1330.                CALL  fdc_write         ; enviar [BP]-H
  1331.                DEC   CH
  1332.                JBE   send_full_ret
  1333.                MOV   AH,BL
  1334.                CALL  fdc_write         ; enviar BL
  1335.                DEC   CH
  1336.                JBE   send_full_ret
  1337.                MOV   AH,BH
  1338.                CALL  fdc_write         ; enviar BH
  1339.                DEC   CH
  1340.                JBE   send_full_ret
  1341.                MOV   AH,CL
  1342.                CALL  fdc_write         ; enviar CL
  1343. send_full_ret: RET
  1344. send_full_cmd  ENDP
  1345.  
  1346. ; ------------ Enviar comando al FDC con/sin espera de interrupción.
  1347.  
  1348. exec_cmd       PROC
  1349.                TEST  BYTE PTR DS:[3Eh],80h  ; ¿hay que esperar IRQ?
  1350.                JZ    exec_cmd_irq           ; sí
  1351.                AND   BYTE PTR DS:[3Eh],7Fh  ; no: devolver a 0 bit IRQ
  1352.                CALL  send_full_cmd          ; enviar comando
  1353.                RET
  1354. exec_cmd_irq:  CALL  send_full_cmd          ; enviar comando
  1355.                JC    exec_cmd_ret
  1356.                MOV   AX,9001h
  1357.                INT   15h                    ; permitir multitarea
  1358.                STI
  1359.                JC    exec_cmd_err
  1360.                CALL  wait_int               ; esperar IRQ
  1361.                JNC   exec_cmd_ok
  1362. exec_cmd_err:  MOV   AH,80h                 ; "not ready" (AH=80h)
  1363. exec_cmd_ret:  RET
  1364. exec_cmd_ok:   AND   BYTE PTR DS:[3Eh],7Fh  ; bit IRQ listo para otra
  1365.                XOR   AH,AH                  ; éxito
  1366.                RET
  1367. exec_cmd       ENDP
  1368.  
  1369. ; ------------ Enviar byte al FDC.
  1370.  
  1371. fdc_write      PROC
  1372.                XPUSH <CX, DX, AX>
  1373.                MOV   DX,3F4h           ; registro de estado del FDC
  1374.                XOR   CX,CX             ; evitar cuelgue total si falla
  1375. espera_wr:     IN    AL,DX             ; leer registro de estado
  1376.                TEST  AL,80h            ; ¿bit 7 inactivo?
  1377.                LOOPZ espera_wr         ; así es: el FDC está ocupado
  1378.                JCXZ  fdc_wr_nok
  1379.                POP   AX
  1380.                PUSH  AX
  1381.                INC   DX                ; apuntar al registro de datos
  1382.                MOV   AL,AH
  1383.                OUT   DX,AL             ; enviar byte al FDC
  1384.                XPOP  <AX, DX, CX>
  1385.                CLC
  1386.                RET
  1387. fdc_wr_nok:    POP   AX
  1388.                MOV   AH,80h            ; timeout
  1389.                XPOP  <DX, CX>
  1390.                STC
  1391.                RET
  1392. fdc_write      ENDP
  1393.  
  1394. ; ------------ Leer del FDC CX bytes de resultado en [BX++].
  1395.  
  1396. get_results    PROC
  1397.                PUSH  DX
  1398. get_one_byte:  PUSH  CX
  1399.                CALL  fdc_read
  1400.                POP   CX
  1401.                JC    get_res_ret       ; no hay más bytes que leer
  1402.                MOV   [BX],AL
  1403.                INC   BX
  1404.                LOOP  get_one_byte      ; leer todos los bytes
  1405.                CALL  retardo53         ; retardo de 53 ms
  1406.                MOV   DX,3F4h
  1407.                IN    AL,DX             ; leer registro de estado
  1408.                TEST  AL,10h
  1409.                JZ    get_res_ok        ; el FDC no está ocupado
  1410.                MOV   AH,20h
  1411.                STC                     ; lo estaba: "bad NEC"
  1412.                JMP   get_res_ret
  1413. get_res_ok:    XOR   AH,AH             ; operación correcta
  1414. get_res_ret:   POP   DX
  1415.                RET
  1416. get_results    ENDP
  1417.  
  1418. ; ------------ Leer byte del FDC.
  1419.  
  1420. fdc_read       PROC
  1421.                XPUSH <CX, DX>
  1422.                MOV   DX,3F4h           ; registro de estado del FDC
  1423.                XOR   CX,CX             ; evitar cuelgue total si falla
  1424. espera_rd:     IN    AL,DX             ; leer registro de estado
  1425.                TEST  AL,80h            ; ¿bit 7 inactivo?
  1426.                LOOPZ espera_rd         ; así es: el FDC está ocupado
  1427.                JCXZ  fdc_rd_nok
  1428.                INC   DX                ; apuntar al registro de datos
  1429.                IN    AL,DX             ; leer byte del FDC
  1430.                CLC
  1431.                XPOP  <DX, CX>
  1432.                RET
  1433. fdc_rd_nok:    MOV   AH,80h            ; timeout
  1434.                STC
  1435.                XPOP  <DX, CX>
  1436.                RET
  1437. fdc_read       ENDP
  1438.  
  1439. ; ------------ Obtener código de error de la BIOS.
  1440.  
  1441. get_bios_err   PROC
  1442.                MOV   BX,42h            ; área de resultados del FDC
  1443.                MOV   BX,[BX]
  1444.                TEST  BL,0C0h           ; ¿que tal ST0?
  1445.                MOV   AH,0
  1446.                JZ    bios_err_det      ; ¡perfecto!
  1447.                TEST  BL,40h            ; ¿terminación brusca/anormal?
  1448.                MOV   AH,20H            ; "bad NEC"
  1449.                JZ    bios_err_det
  1450.                TEST  BH,1              ; ¿falta marca de direcciones?
  1451.                MOV   AH,2              ; "address mark not found"
  1452.                JNZ   bios_err_det
  1453.                TEST  BH,2              ; ¿protegido contra escritura?
  1454.                MOV   AH,3              ; "write-protect error"
  1455.                JNZ   bios_err_det
  1456.                TEST  BH,4              ; ¿sector no encontrado?
  1457.                MOV   AH,4              ; "sector not found"
  1458.                JNZ   bios_err_det
  1459.                TEST  BH,10H            ; ¿DMA no atendido a tiempo?
  1460.                MOV   AH,8              ; "DMA overrun"
  1461.                JNZ   bios_err_det
  1462.                TEST  BH,20H            ; ¿falla el CRC?
  1463.                MOV   AH,10H            ; "CRC error"
  1464.                JNZ   bios_err_det
  1465.                TEST  BH,80h            ; ¿acceso fuera de la pista?
  1466.                MOV   AH,4              ; "sector not found"
  1467.                JNZ   bios_err_det
  1468.                MOV   AH,20H            ; otro error: "bad NEC"
  1469. bios_err_det:  RET
  1470. get_bios_err   ENDP
  1471.  
  1472. ; ------------ Reinicializar la controladora de disquetes.
  1473.  
  1474. init_fdc       PROC
  1475.                CALL  reset_disk        ; resetear FDC
  1476.                JC    init_fin          ; fallo al resetear
  1477.                MOV   DX,3F4h           ; registro de estado del FDC
  1478.                IN    AL,DX
  1479.                TEST  AL,80h
  1480.                JZ    init_otravez      ; el FDC no está listo
  1481.                TEST  AL,40h
  1482.                JZ    init_bien         ; el FDC espera datos de la CPU
  1483. init_otravez:  CALL  reset_disk        ; otro intento más
  1484.                MOV   DX,3F4h
  1485.                IN    AL,DX
  1486.                TEST  AL,80h
  1487.                JZ    init_mal          ; nada, que no tira
  1488.                TEST  AL,40h
  1489.                JZ    init_bien         ; bueno, ya despierta
  1490. init_mal:      MOV   AH,20h            ; fallo de la controladora
  1491.                STC
  1492.                JMP   init_fin
  1493. init_bien:     MOV   AH,8              ; "leer estado interrupciones"
  1494.                CALL  fdc_write         ; enviar comando
  1495.                JC    init_fin          ; fallo
  1496.                CALL  fdc_read          ; leer ST0
  1497.                JC    init_fin          ; fallo
  1498.                MOV   DS:[42h],AL       ; guardar ST0
  1499.                PUSH  AX
  1500.                CALL  fdc_read          ; leer cilindro actual
  1501.                MOV   DS:[42h+1],AL     ; guardarlo
  1502.                POP   CX
  1503.                JC    init_fin          ; fallo
  1504.                AND   CL,0C0h
  1505.                CMP   CL,0C0h           ; ¿terminación anormal?
  1506.                JNE   init_mal          ; no es terminación anormal
  1507.                XOR   AH,AH             ; ok: el FDC detecta el fallo
  1508. init_fin:      JMP   fdc_init
  1509. init_fdc       ENDP
  1510.  
  1511. ; ------------ Resetear el FDC.
  1512.  
  1513. reset_disk     PROC
  1514.                CLI
  1515.                AND   BYTE PTR DS:[3Fh],7Fh  ; operación R/V
  1516.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1517.                MOV   AL,DS:[3Fh]
  1518.                XROL  AL,4              ; bits 7-4: motores
  1519.                AND   AL,0FBH           ; bits 3-0: unidad
  1520.                OR    AL,8              ; interrupciones ON + reset
  1521.                MOV   DX,3F2h
  1522.                OUT   DX,AL             ; hacer reset
  1523.                XOR   CX,CX
  1524.                CALL  retardo53         ; pequeño retardo
  1525.                OR    AL,0CH
  1526.                OUT   DX,AL             ; fin del reset
  1527.                MOV   AX,9001h
  1528.                INT   15h               ; facilitar multitarea
  1529.                STI
  1530.                JC    fin_wait          ; error
  1531.                CALL  wait_int          ; esperar interrupción de disco
  1532. fin_wait:      MOV   AH,80h            ; "unidad no preparada"
  1533.                JC    exit_reset        ; hay error
  1534.                AND   BYTE PTR DS:[3Eh],7Fh  ; borrar bit IRQ
  1535.                XOR   AH,AH                  ; no hay error
  1536. exit_reset:    RET
  1537. reset_disk     ENDP
  1538.  
  1539. ; ------------ Enviar comando specify obtenido de INT 1Eh al FDC.
  1540.  
  1541. send_specify   PROC
  1542.                PUSH  DS
  1543.                XOR   BX,BX
  1544.                MOV   DS,BX
  1545.                LDS   BX,DWORD PTR DS:[78h]  ; DS:BX -> INT 1Eh
  1546.                MOV   AL,3                   ; comando specify del FDC
  1547.                MOV   AH,[BX]           ; byte 0 del comando specify
  1548.                MOV   SI,AX
  1549.                MOV   AL,[BX+1]         ; byte 1 del comando specify
  1550.                MOV   DI,AX
  1551.                MOV   CH,3              ; orden de 3 bytes (SI, DI-L)
  1552.                POP   DS
  1553.                OR    BYTE PTR DS:[3Eh],80h  ; no esperar IRQ
  1554.                CALL  exec_cmd           ; mandar specify al FDC
  1555.                JMP   specify_sent
  1556. send_specify   ENDP
  1557.  
  1558. ; ------------ Esperar una interrupción de disco durante 2 segundos.
  1559.  
  1560. wait_int       PROC
  1561.                MOV   BX,3Eh            ; variable con flag de INT
  1562.                MOV   CX,37
  1563.                CALL  wait_event        ; esperar IRQ durante 2 seg.
  1564.                RET
  1565. wait_int       ENDP
  1566.  
  1567. ; ------------ Devolver en AL el tipo de la unidad DL.
  1568.  
  1569. get_drive_type PROC
  1570.                CALL  peek_cmos         ; leer tipo de disqueteras
  1571.                OR    DL,DL
  1572.                JNZ   gdt_unidad_ok
  1573.                XSHR  AL,4              ; unidad A:
  1574. gdt_unidad_ok: AND   AL,0Fh
  1575.                CMP   SP,SP             ; ZF=1 -> resultado correcto
  1576.                RET
  1577. get_drive_type ENDP
  1578.  
  1579. ; ------------ Determinar la densidad del disquete.
  1580.  
  1581. detect_media   PROC
  1582.                PUSH  DX
  1583.                PUSH  CX
  1584.                PUSH  BX
  1585.                MOV   BL,r_dl
  1586.                XOR   BH,BH
  1587.                MOV   DL,BL
  1588.                CALL  get_drive_type    ; obtener tipo disquetera en AL
  1589.                MOV   AH,0
  1590.                JZ    dm_fast           ; ha sido posible obtenerlo
  1591.                JMP   dm_slow           ; usar procedimiento lento
  1592. dm_fast:       MOV   BYTE PTR DS:[BX+90h],0  ; estado físico unidad
  1593.                DEC   AX
  1594.                JNZ   dm_es_1200K?
  1595.                MOV   AL,93h            ; 360K: 360K en 360K, 250 Kbps
  1596. dm_try:        PUSH  AX
  1597.                MOV   DH,AL
  1598.                AND   DH,0C0h
  1599.                XSHR  DH,6
  1600.                CALL  set_rate          ; velocidad de transferencia DH
  1601.                POP   AX
  1602. dm_result:     MOV   DS:[BX+90h],AL    ; estado físico...
  1603.                TEST  AL,10h            ; ...¿determinado?
  1604.                JZ    dm_fails          ; aún no
  1605.                XOR   AH,AH
  1606.                JMP   dm_exit           ; sí: resultado correcto
  1607.                NOP
  1608. dm_es_1200K?:  DEC   AX
  1609.                JNZ   dm_es_720K?
  1610.                MOV   AL,0              
  1611.                CALL  read_ids          ; 1.2M: 500 kbps
  1612.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1613.                JNC   dm_result         ; sí funciona
  1614.                MOV   AL,40h
  1615.                MOV   BYTE PTR DS:[BX+90h],2
  1616.                CALL  read_ids          ; probar 300 Kbps
  1617.                MOV   AL,74h            ; indicar 360K en 1.2M
  1618.                JNC   dm_result         ; sí funciona
  1619.                MOV   AL,2              ; indicar "¿1.2M en 1.2M?"
  1620.                JMP   dm_result
  1621. dm_es_720K?:   DEC   AX
  1622.                JNZ   dm_es_1440K?
  1623.                MOV   AL,97h            ; 720K: 250 Kbps
  1624.                JMP   dm_try            ; a probar suerte
  1625. dm_es_1440K?:  DEC   AX
  1626.                JNZ   dm_es_2880K
  1627.                MOV   AL,0
  1628.                CALL  read_ids          ; 1.44M: 500 Kbps
  1629.                MOV   AL,17h            ; indicar 1.44M
  1630.                JNC   dm_result         ; sí funciona
  1631.                MOV   AL,80h
  1632.                CALL  read_ids          ; probar a 250 Kbps
  1633.                MOV   AL,97h            ; indicar 720K
  1634.                JNC   dm_result         ; sí funciona
  1635.                MOV   AL,7              ; indicar "¿1.44M?"
  1636.                JMP   dm_result
  1637. dm_es_2880K:   MOV   AL,0C0h
  1638.                CALL  read_ids          ; 2.88M: 1 Mbps
  1639.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1640.                JNC   dm_result         ; sí funciona
  1641.                MOV   AL,0
  1642.                CALL  read_ids          ; probar 500 Kbps
  1643.                MOV   AL,17h            ; indicar 1.44M
  1644.                JNC   dm_result         ; sí funciona
  1645.                MOV   AL,80h
  1646.                CALL  read_ids          ; probar 250 Kbps
  1647.                MOV   AL,97h            ; indicar 720K
  1648.                JNC   dm_result         ; sí funciona
  1649.                MOV   AL,0C7h           ; indicar "¿2.88M en 2.88M?"
  1650.                JMP   dm_result
  1651. dm_fails:      STC                     ; condición de error
  1652. dm_exit:       MOV   DS:[41h],AH       ; código de error
  1653.                POP   BX
  1654.                POP   CX
  1655.                POP   DX
  1656.                RET
  1657. dm_slow:       MOV   AL,0
  1658.                CALL  read_ids          ; probar 500 Kbps
  1659.                MOV   AL,15h            ; indicar 1.2M en 1.2M
  1660.                JNC   dm_slow_ok        ; sí funciona
  1661.                MOV   AL,40h
  1662.                MOV   BYTE PTR DS:[BX+90h],2
  1663.                CALL  read_ids          ; probar 300 Kbps
  1664.                MOV   AL,74h            ; indicar 360K en 1.2M
  1665.                JNC   dm_slow_ok        ; sí funciona
  1666.                MOV   AL,80h
  1667.                CALL  read_ids          ; probar 250 Kbps
  1668.                MOV   AL,97h            ; indicar 720K ó 360K en 360K
  1669.                JNC   dm_slow_ok        ; sí funciona
  1670.                MOV   AL,0C0h
  1671.                CALL  read_ids          ; probar 1 Mbps
  1672.                MOV   AL,0D7h           ; indicar 2.88M en 2.88M
  1673.                JC    dm_fails          ; no funciona
  1674. dm_slow_ok:    JMP   dm_result
  1675. detect_media   ENDP
  1676.  
  1677. ; ------------ Efectuar una lectura de ID's a velocidad AL (bits 6-7).
  1678.  
  1679. read_ids       PROC
  1680.                PUSH  BX
  1681.                PUSHF
  1682.                CLI
  1683.                MOV   BYTE PTR DS:[40h],0FFh  ; evitar detención motor
  1684.                POPF
  1685.                XSHR  AL,6              ; colocar bits de velocidad
  1686.                MOV   DH,AL
  1687.                CALL  set_rate          ; velocidad de transferencia DH
  1688.                MOV   DL,r_dl
  1689.                CALL  recalibrate       ; recalibrar
  1690.                JNC   read_id_try
  1691.                CALL  recalibrate       ; segundo intento
  1692.                JC    read_id_err
  1693. read_id_try:   MOV   CX,3              ; 3 intentos
  1694. read_id_retry: PUSH  CX
  1695.                MOV   DH,DL             ; en el cabezal 0 de la unidad
  1696.                MOV   DL,4Ah            ; comando de leer ID's
  1697.                MOV   SI,DX
  1698.                MOV   DL,DH
  1699.                MOV   CH,2              ; comando de 2 bytes
  1700.                AND   BYTE PTR DS:[3Eh],7Fh  ; esperar interrupción
  1701.                CALL  exec_cmd
  1702.                JC    read_id_fails     ; fallo
  1703.                MOV   BX,42h
  1704.                MOV   CX,7
  1705.                CALL  get_results       ; leer bytes de resultados
  1706.                JC    read_id_fails
  1707.                CALL  get_bios_err      ; obtener código de error
  1708.                POP   CX
  1709.                OR    AH,AH
  1710.                JZ    read_id_ret       ; ya no hay fallo
  1711.                LOOP  read_id_retry     ; reintentar
  1712.                JMP   read_id_err       ; mala suerte
  1713. read_id_fails: POP   CX
  1714. read_id_err:   STC
  1715. read_id_ret:   POP   BX
  1716.                RET
  1717. read_ids       ENDP
  1718.  
  1719. ; ------------ Seleccionar la velocidad de transferencia adecuada.
  1720.  
  1721. select_rate    PROC
  1722.                PUSH  SI
  1723.                MOV   SI,90h
  1724.                XOR   DH,DH
  1725.                ADD   SI,DX             ; [SI] -> estado físico unidad
  1726.                MOV   DH,[SI]           ; estado físico nueva unidad
  1727.                MOV   DL,DS:[8Bh]       ; control del medio físico
  1728.                AND   DX,0C0C0h         ; aislar bits de velocidad
  1729.                CMP   DL,DH             ; ¿velocidad ya seleccionada?
  1730.                JE    selected_rate
  1731.                AND   BYTE PTR DS:[8Bh],3Fh  ; no: borrar la anterior
  1732.                OR    DS:[8Bh],DH            ; indicar la nueva
  1733.                AND   DH,0C0h
  1734.                XROL  DH,2
  1735.                CALL  set_rate          ; nueva velocidad transferencia
  1736. selected_rate: POP   SI
  1737.                MOV   DX,r_dx           ; restaurar DX
  1738.                RET
  1739. select_rate    ENDP
  1740.  
  1741. ; ------------ Establecer la velocidad de transferencia DH.
  1742.  
  1743. set_rate       PROC
  1744.                PUSH  AX
  1745.                MOV   AL,DH
  1746.                MOV   DX,3F7h      ; registro de control del disquete
  1747.                OUT   DX,AL        ; seleccionar velocidad
  1748.                POP   AX
  1749.                RET
  1750. set_rate       ENDP
  1751.  
  1752. ; ------------ Esperar evento durante CX 18.2-avos de segundo.
  1753.  
  1754. wait_event     PROC
  1755.                PUSH  AX
  1756. test_55ms:     MOV   AL,DS:[6Ch]
  1757. test_int:      TEST  BYTE PTR [BX],80h
  1758.                JNZ   fin_w_event       ; llegó la interrupción
  1759. w_timer:       CMP   AL,DS:[6Ch]
  1760.                JE    test_int
  1761.                LOOP  test_55ms
  1762.                STC                     ; no llegó la interrupción
  1763. fin_w_event:   POP   AX
  1764.                RET
  1765. wait_event     ENDP
  1766.  
  1767. ; ------------ Simular la lectura del registro 10h de la CMOS, para
  1768. ;              el tipo de las disqueteras.
  1769.  
  1770. peek_cmos      PROC
  1771.                MOV   AL,CS:tipo_drvs   ; nuestro tipo simulado
  1772.                RET
  1773. peek_cmos      ENDP
  1774.  
  1775. ; ------------ Esperar exactamente CX milisegundos.
  1776.  
  1777. retardo        PROC
  1778.                PUSHF
  1779.                XPUSH <AX, BX, CX, DX>
  1780. retarda_mas:   CMP   CX,54             ; como máximo 54 ms cada vez
  1781.                JBE   retarda_fin
  1782.                PUSH  CX
  1783.                MOV   AX,54
  1784.                CALL  rt_ax
  1785.                POP   CX
  1786.                SUB   CX,54
  1787.                JMP   retarda_mas
  1788. retarda_fin:   MOV   AX,CX
  1789.                CALL  rt_ax
  1790.                XPOP  <DX, CX, BX, AX>
  1791.                POPF
  1792.                RET
  1793.  
  1794. rt_ax:         PUSH  CX
  1795.                MOV   DX,1000           ; retardo de hasta 54 ms
  1796.                MUL   DX
  1797.                MUL   CS:tbase
  1798.                MOV   CX,54925
  1799.                DIV   CX                ; AX = contador iteraciones
  1800.                MOV   CX,AX
  1801.                EVEN                    ; forzar alineamiento
  1802. retarda:       DEC   CX
  1803.                JMP   SHORT $+2
  1804.                JNZ   retarda
  1805.                POP   CX
  1806.                RET
  1807. retardo        ENDP
  1808.  
  1809. retardo53      PROC
  1810.                MOV   CX,CS:tbase
  1811.                MOV   CL,CH
  1812.                MOV   CH,0
  1813.                SHR   CX,1
  1814.                SHR   CX,1
  1815.                EVEN                    ; forzar alineamiento
  1816. retarda_res:   DEC   CX
  1817.                JMP   SHORT $+2
  1818.                JNZ   retarda_res       ; pausa de 53 µs
  1819.                RET
  1820. retardo53      ENDP
  1821.  
  1822. ; ------------ Datos.
  1823.  
  1824. tipo_drvs      DB    0    ; tipo de disqueteras (definido al instalar)
  1825. tbase          DW    ?    ; cte de tiempo para bucles de retardo
  1826.  
  1827.                ; --- Tabla de saltos a las funciones
  1828.  
  1829. tab_jmp        DW    reset, get_status
  1830.                DW    read_wr_verify, read_wr_verify, read_wr_verify
  1831.                DW    format_track, get_drv_param, get_disk_type
  1832.                DW    detect_change, set_type_fmt, set_media_fmt
  1833.  
  1834.                ; --- Tabla de tamaños en sectores y cilindros
  1835.  
  1836. tab_disksize   DW     9 + 39 * 256  ; 360K
  1837.                DW    15 + 79 * 256  ; 1.2M
  1838.                DW     9 + 79 * 256  ; 720K
  1839.                DW    18 + 79 * 256  ; 1.44M
  1840.                DW    36 + 79 * 256  ; 2.88M
  1841.  
  1842.                ; --- Tablas de parámetros de disco (sintaxis INT 1Eh)
  1843.  
  1844. tab_ptr_1e     DW    t360in360, t1200, t720, t1440, t2880
  1845.  
  1846.                ; Bytes de esta tabla, similar a la de INT 1Eh:
  1847.                ;
  1848.                ;     0) byte 1 para 'Specify' (step rate-head unload)
  1849.                ;     1) byte 2 para 'Specify' (head load-modo DMA)
  1850.                ;     2) tics de reloj hasta detención del motor
  1851.                ;     3) tamaño de sector (0-128, 1-256, 2-512, ...)
  1852.                ;     4) sectores por pista
  1853.                ;     5) GAP3 para lectura/escritura
  1854.                ;     6) longitud concreta de sector si tamaño=0
  1855.                ;     7) GAP3 para formateo
  1856.                ;     8) byte de relleno al formatear
  1857.                ;     9) tiempo de estabilización del cabezal en ms
  1858.                ;    10) tiempo aceleración motor, en 1/8 segundos
  1859.                ;    11) número de cilindros menos uno
  1860.                ;    12) velocidad de transferencia (en bits 6-7)
  1861.  
  1862. t360in360      DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 360K
  1863.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1864.                DB    008h, 027h, 080h
  1865. t1200          DB    0DFh, 002h, 025h, 002h, 00Fh   ; 1.2M
  1866.                DB    01Bh, 0FFh, 054h, 0F6h, 00Fh
  1867.                DB    008h, 04Fh, 000h
  1868. t720           DB    0DFh, 002h, 025h, 002h, 009h   ; 720K
  1869.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1870.                DB    008h, 04Fh, 080h
  1871. t1440          DB    0BFh, 002h, 025h, 002h, 012h   ; 1.44M
  1872.                DB    01Bh, 0FFh, 06Ch, 0F6h, 00Fh
  1873.                DB    008h, 04Fh, 000h
  1874. t360en1200     DB    0DFh, 002h, 025h, 002h, 009h   ; 360K en 1.2M
  1875.                DB    02Ah, 0FFh, 050h, 0F6h, 00Fh
  1876.                DB    008h, 027h, 040h
  1877. t2880          DB    0AFh, 002h, 025h, 002h, 024h   ; 2.88M
  1878.                DB    01Bh, 0FFh, 050h, 0F6h, 00Fh
  1879.                DB    008h, 04Fh, 0C0h
  1880.  
  1881.                ; --- Fin del área residente para INT 40h
  1882.  
  1883. fin_residente  EQU   $
  1884.  
  1885. bytes_resid    EQU   fin_residente-ini_residente
  1886.  
  1887. ; ------------ Rutina de gestión de INT 13h (si se necesita). Se llama
  1888. ;              a la INT 40h de manera que esta última no devuelva
  1889. ;              nunca errores de frontera de DMA, para lo que emplea un
  1890. ;              buffer auxiliar de 512 bytes para transferir el sector
  1891. ;              que cruzaría la frontera. En la función de formateo, al
  1892. ;              acceder a la primera pista del disco se invoca primero
  1893. ;              la interrupción original para que el DOS (cargado antes
  1894. ;              que este programa) se entere del cambio de soporte.
  1895.  
  1896. ges_int13      PROC
  1897.                STI
  1898.                CMP   DL,80h
  1899.                JB    floppy
  1900.                JMP   CS:ant_int13
  1901. floppy:        CMP   AH,2
  1902.                JB    floppy_bios
  1903.                CMP   AH,5
  1904.                JE    test_format
  1905.                JB    test_rwv
  1906. floppy_bios:   INT   40h               ; función sin problemas de DMA
  1907.                RETF  2
  1908. ges_int13      ENDP
  1909.  
  1910. test_format    PROC
  1911.                XPUSH <DS, ES, BX>
  1912.                XPUSHA
  1913.                PUSH  DX
  1914.                OR    DH,CH
  1915.                POP   DX
  1916.                JNZ   skip_aviso        ; no es pista y cabezal 0
  1917.                XPUSHA
  1918.                MOV   AL,1              ; formatear un sector (AH=5)
  1919.                MOV   CH,0
  1920.                MOV   DH,2              ; en cabezal 2 (incorrecto)
  1921.                PUSHF
  1922.                CALL  CS:ant_int13      ; avisar al DOS del nuevo disco
  1923.                XPOPA
  1924. skip_aviso:    MOV   DI,CS:pbuffer
  1925.                MOV   SI,BX
  1926.                PUSH  ES
  1927.                POP   DS
  1928.                PUSH  CS
  1929.                POP   ES
  1930.                MOV   CX,256
  1931.                CLD
  1932.                REP   MOVSW             ; datos de formateo al buffer
  1933.                XPOPA                   ; auxiliar
  1934.                MOV   BX,CS:pbuffer
  1935.                INT   40h               ; formateo
  1936.                XPOP  <BX, ES, DS>      ; restaurar registros iniciales
  1937.                RETF  2
  1938. test_format    ENDP
  1939.  
  1940. test_rwv       PROC                    ; para Read/Write/Verify
  1941.                MOV   CS:funcion,AH
  1942.                MOV   CS:nsects,AL
  1943.                XPUSH <SI, DI>
  1944.                XPUSH <AX, DX>
  1945.                MOV   AX,ES
  1946.                MOV   DX,16
  1947.                MUL   DX
  1948.                ADD   AX,BX
  1949.                NEG   AX                ; AX = bytes hasta frontera DMA
  1950.                XSHR  AX,9
  1951.                MOV   SI,AX             ; sectores antes frontera
  1952.                XPOP  <DX, AX>
  1953.                PUSH  AX
  1954.                MOV   AH,0
  1955.                MOV   DI,AX
  1956.                POP   AX
  1957.                CMP   SI,DI
  1958.                JBE   trwv_no_sobra
  1959.                MOV   SI,DI
  1960. trwv_no_sobra: SUB   DI,SI             ; sectores+1 tras frontera
  1961.                JZ    trwv_1ok
  1962.                PUSH  CX
  1963.                MOV   CX,SI
  1964.                MOV   AL,CL             ; AL sectores antes de frontera
  1965.                POP   CX
  1966. trwv_1ok:      AND   AL,AL
  1967.                JZ    trwv_1cruza       ; primer sector cruza frontera
  1968.                INT   40h
  1969.                PUSHF
  1970.                JNC   trwv_cont         ; sin fallo E/S
  1971. trwv_exit:     JMP   trwv_ret
  1972. trwv_cont:     AND   DI,DI
  1973.                JZ    trwv_exit         ; se acabó
  1974.                POPF
  1975. trwv_1cruza:   CMP   CS:funcion,3      ; ¿escritura?
  1976.                JNE   trwv_sectdma
  1977.                XPUSHA
  1978.                XPUSH <DS, ES>
  1979.                XSHL  SI,9              ; sectores transferidos * 512
  1980.                ADD   SI,BX
  1981.                MOV   DI,CS:pbuffer
  1982.                PUSH  ES
  1983.                POP   DS
  1984.                PUSH  CS
  1985.                POP   ES
  1986.                MOV   CX,256
  1987.                CLD
  1988.                REP   MOVSW             ; sector conflictivo a través
  1989.                XPOP  <ES, DS>          ; de buffer auxiliar
  1990.                XPOPA
  1991. trwv_sectdma:  XPUSH <ES, BX, CX>
  1992.                PUSH  CS
  1993.                POP   ES
  1994.                MOV   BX,CS:pbuffer     ; ES:BX buffer auxiliar
  1995.                MOV   AH,CS:funcion
  1996.                MOV   AL,1              ; un sector
  1997.                ADD   CX,SI             ; nuevo sector inicial
  1998.                INT   40h
  1999.                XPOP  <CX, BX, ES>
  2000.                PUSHF
  2001.                JC    trwv_ret          ; fallo E/S
  2002.                CMP   CS:funcion,2      ; ¿lectura?
  2003.                JNE   trwv_tras?
  2004.                XPUSHA
  2005.                XPUSH <DS, ES>
  2006.                XSHL  SI,9              ; sectores transferidos * 512
  2007.                MOV   DI,SI
  2008.                ADD   DI,BX
  2009.                MOV   SI,CS:pbuffer
  2010.                PUSH  CS
  2011.                POP   DS
  2012.                MOV   CX,256
  2013.                CLD
  2014.                REP   MOVSW             ; sector conflictivo a través
  2015.                XPOP  <ES, DS>          ; de buffer auxiliar
  2016.                XPOPA
  2017. trwv_tras?:    MOV   AL,CS:nsects      ; sectores transferidos
  2018.                DEC   DI
  2019.                JZ    trwv_ret          ; no queda nada tras frontera
  2020.                POPF
  2021.                XPUSH <BX, CX>
  2022.                INC   SI
  2023.                ADD   CX,SI             ; nuevo sector inicial
  2024.                XSHL  SI,9              ; sectores transferidos * 512
  2025.                ADD   BX,SI
  2026.                MOV   AX,DI             ; sectores restantes
  2027.                MOV   AH,CS:funcion
  2028.                INT   40h
  2029.                XPOP  <CX, BX>
  2030.                MOV   AL,CS:nsects      ; número sectores transferidos
  2031.                PUSHF
  2032. trwv_ret:      POPF
  2033.                XPOP  <DI, SI>
  2034.                RETF  2
  2035. test_rwv       ENDP
  2036.  
  2037. funcion        DB    ?
  2038. nsects         DB    ?
  2039. pbuffer        DW    buffer_io
  2040.  
  2041.                EVEN
  2042. buffer_io      EQU   $
  2043.  
  2044.  
  2045. ; *****************************
  2046. ; *                           *
  2047. ; *   I N S T A L A C I O N   *
  2048. ; *                           *
  2049. ; *****************************
  2050.  
  2051. main           PROC
  2052.                ADD   SP,2              ; quitar dirección de retorno
  2053.                XPUSH <AX, BX, CX, DX, SI, DI, BP, DS, ES>
  2054.                PUSH  CS
  2055.                POP   DS
  2056.                MOV   WORD PTR interrupcion,531Eh  ; opcode PUSH DS,BX
  2057.                MOV   BYTE PTR interrupcion+2,0BBh ; opcode MOV BX,??
  2058.                PUSH  CS
  2059.                POP   ES
  2060.                CALL  inic_general      ; inicializar ciertas variables
  2061.                CALL  analiza_equipo
  2062.                CALL  lee_params        ; parámetros de tipo unidades
  2063.                CALL  set_params        ; actualizar tipo de unidades
  2064.                CALL  valida_drives     ; asegurar que hay unidades
  2065.                TEST  error,0FFFFh
  2066.                JNZ   exit_ins
  2067.                CALL  hay2m?
  2068.                JC    no_2m
  2069.                OR    error,ERR_HAY2M   ; 2M ó 2MX residente
  2070.                JMP   exit_ins
  2071. no_2m:         TEST  accion,I40        ; ¿soporta INT 40h el sistema?
  2072.                JNZ   i40_ok            ; en efecto
  2073.                CALL  set_i13           ; añadir soporte vía INT 13h
  2074. i40_ok:        CALL  cte_tiempos
  2075.                MOV   tbase,AX
  2076.                CALL  init_vars
  2077.                CALL  mx_get_handle     ; obtener entrada Multiplex
  2078.                JNC   handle_ok
  2079.                OR    error,MX64FULL    ; no quedan entradas
  2080.                JMP   exit_ins
  2081. handle_ok:     MOV   multiplex_id,AH   ; entrada multiplex para 2M
  2082.                CALL  preservar_ints    ; tomar nota de vectores
  2083.                CALL  activar_ints      ; interceptar vectores
  2084.                CALL  set_dev_params    ; establecer tipo unidades DOS
  2085. exit_ins:      CALL  info
  2086.                MOV   BX,pcab_pet_segm
  2087.                MOV   ES,BX
  2088.                MOV   BX,pcab_pet_desp
  2089.                MOV   WORD PTR ES:[BX+3],100h ; indicar retorno correcto
  2090.                MOV   AX,longitud_total
  2091.                MOV   CL,4
  2092.                SHL   AX,CL
  2093.                TEST  error,0FFFFh
  2094.                JZ    exit_ok
  2095.                MOV   WORD PTR ES:[BX+14],0   ; OFFSET 0: no quedará
  2096.                MOV   WORD PTR ES:[BX+16],CS  ; instalado en memoria
  2097.                JMP   exit_interr
  2098. exit_ok:       MOV   WORD PTR ES:[BX+14],AX  ; OFFSET al último byte residente
  2099.                MOV   WORD PTR ES:[BX+16],CS
  2100. exit_interr:   XPOP  <ES, DS, BP, DI, SI, DX, CX, BX, AX>
  2101.                RETF
  2102. main           ENDP
  2103.  
  2104. ; ------------ Leer los parámetros en la línea del CONFIG (ES:BX).
  2105.  
  2106. lee_params     PROC
  2107.                PUSH  ES
  2108.                MOV   BX,pcab_pet_segm
  2109.                MOV   ES,BX
  2110.                MOV   BX,pcab_pet_desp
  2111.                LES   BX,ES:[BX+12h]    ; apuntar a los parámetros
  2112.                CALL  salta_nombre      ; buscar inicio parámetros
  2113. mas_param:     CALL  busca_param       ; saltar delimitadores
  2114.                JC    fin_params        ; no hay parámetros
  2115. otro_drive:    CMP   AX,':a'
  2116.                JE    unidad_ok
  2117.                CMP   AX,':b'           ; admitidas A: y B:
  2118.                JE    unidad_ok
  2119. param_error:   OR    error,ERR_SYNTAX  ; error de sintaxis
  2120.                POP   ES
  2121.                RET
  2122. unidad_ok:     MOV   CL,ES:[BX+2]
  2123.                SUB   CL,'0'            ; tipo de la unidad
  2124.                SUB   AL,'a'
  2125.                MOV   AH,0
  2126.                LEA   DI,tipos_drv
  2127.                ADD   DI,AX
  2128.                CMP   CL,5              ; ¿tipo entre 0 y 5?
  2129.                JA    param_error
  2130.                MOV   [DI],CL           ; definir tipo
  2131.                ADD   BX,3
  2132.                JMP   mas_param         ; próximo parámetro
  2133. fin_params:    POP   ES
  2134.                RET
  2135. lee_params     ENDP
  2136.  
  2137. salta_nombre   PROC                    ; saltar nombre del driver en
  2138.                MOV   AL,ES:[BX]        ; línea de órdenes del CONFIG
  2139.                INC   BX
  2140.                CMP   AL,' '
  2141.                JE    fin_nombre
  2142.                CMP   AL,9
  2143.                JE    fin_nombre
  2144.                CMP   AL,0Dh
  2145.                JE    fin_nombre
  2146.                CMP   AL,0Ah
  2147.                JE    fin_nombre
  2148.                AND   AL,AL
  2149.                JZ    fin_nombre
  2150.                JMP   salta_nombre
  2151. fin_nombre:    RET
  2152. salta_nombre   ENDP
  2153.  
  2154. busca_param    PROC                    ; saltar delimitadores
  2155.                DEC   BX
  2156. p_delimit:     INC   BX
  2157.                MOV   AX,ES:[BX]
  2158.                CMP   AL,' '
  2159.                JE    p_delimit         ; espacio en blanco
  2160.                CMP   AL,9
  2161.                JE    p_delimit         ; tabulador
  2162.                CMP   AL,13
  2163.                JE    p_final           ; CR ó LF indican el final
  2164.                CMP   AL,10
  2165.                JE    p_final
  2166.                OR    AX,"  "           ; poner en minúsculas
  2167.                CLC
  2168.                RET
  2169. p_final:       STC                     ; se acabaron los parámetros
  2170.                RET
  2171. busca_param    ENDP
  2172.  
  2173. ; ------------ Establecer tipo disqueteras (según BIOS o parámetros).
  2174.  
  2175. set_params     PROC
  2176.                PUSH  ES
  2177.                MOV   AL,tipos_drv
  2178.                CMP   AL,-1
  2179.                JNE   ta_calc           ; A: definida por el usuario
  2180.                MOV   AH,8
  2181.                MOV   DL,0
  2182.                INT   13h               ; consultar tipo a la BIOS
  2183.                MOV   AL,BL
  2184.                JNC   ta_val
  2185.                JMP   set_type_exit     ; unidad no existente
  2186. ta_val:        CMP   DL,1
  2187.                JB    set_type_exit
  2188. ta_calc:       CMP   AL,4
  2189.                JBE   ta_set
  2190.                MOV   AL,5              ; 2.88M representado por 5
  2191. ta_set:        AND   tipo_drvs,0Fh
  2192.                MOV   CL,4
  2193.                SHL   AL,CL
  2194.                OR    tipo_drvs,AL      ; tipo A: en nibble alto
  2195.                MOV   AL,tipos_drv+1
  2196.                CMP   AL,-1             ; B: definida por el usuario
  2197.                JNE   tb_calc
  2198.                MOV   AH,8
  2199.                MOV   DL,1
  2200.                INT   13h               ; consultar tipo a la BIOS
  2201.                MOV   AL,BL
  2202.                JC    set_type_exit
  2203.                CMP   DL,2
  2204.                JB    set_type_exit     ; unidad no existente
  2205. tb_calc:       CMP   AL,4
  2206.                JBE   tb_set
  2207.                MOV   AL,5              ; 2.88M representado por 5
  2208. tb_set:        AND   tipo_drvs,0F0h
  2209.                OR    tipo_drvs,AL      ; tipo B: en nibble bajo
  2210. set_type_exit: POP   ES
  2211.                RET
  2212. set_params     ENDP
  2213.  
  2214. ; ------------ Asegurar que se conoce el tipo de las unidades.
  2215.  
  2216. valida_drives  PROC
  2217.                MOV   AL,tipo_drvs
  2218.                AND   AL,0F0h
  2219.                JNZ   drvs_ok
  2220.                OR    error,ERR_MALDRV
  2221. drvs_ok:       RET
  2222. valida_drives  ENDP
  2223.  
  2224. ; ------------ Código ejecutado desde la línea de comandos.
  2225.  
  2226. inicio         PROC  FAR
  2227.                MOV   AX,_PRINCIPAL
  2228.                MOV   DS,AX
  2229.                CALL  param_i?
  2230.                MOV   AX,DS
  2231.                MOV   ES,AX
  2232.                CALL  residente?
  2233.                JC    dos_info
  2234.                CALL  cte_tiempos
  2235.                MOV   ES,tsr_seg
  2236.                MOV   ES:tbase,AX
  2237.                LEA   DX,info_adj_txt
  2238.                CALL  print
  2239.                CMP   param_hlp,ON
  2240.                JE    dos_info
  2241.                JMP   dos_exit
  2242. dos_info:      LEA   DX,info_txt
  2243.                CALL  print
  2244. dos_exit:      MOV   AX,4C00h
  2245.                INT   21h                    ; final normal
  2246. inicio         ENDP
  2247.  
  2248.                ; ----- Buscar posible parámetro /I ó /?
  2249.  
  2250. param_i?       PROC
  2251.                MOV   DI,80h
  2252.                MOV   CL,ES:[DI]
  2253.                MOV   CH,0
  2254.                INC   CX
  2255. busca_mas:     MOV   DL,OFF
  2256.                JCXZ  ret_bparam
  2257. busca_barra:   INC   DI
  2258.                CMP   BYTE PTR ES:[DI],'/'
  2259.                LOOPNE busca_barra
  2260.                JNE   ret_bparam
  2261.                MOV   AL,ES:[DI+1]
  2262.                OR    AL,32
  2263.                MOV   DL,ON
  2264.                CMP   AL,'i'
  2265.                JE    pmt_i
  2266.                CMP   AL,'?'
  2267.                JE    pmt_hlp
  2268.                CMP   AL,'h'
  2269.                JE    pmt_hlp
  2270.                JMP   busca_mas
  2271. pmt_i:         MOV   param_i,DL
  2272.                JMP   busca_mas
  2273. pmt_hlp:       MOV   param_hlp,DL
  2274.                JMP   busca_mas
  2275. ret_bparam:    RET
  2276. param_i?       ENDP
  2277.  
  2278. ; ------------ Inicializar ciertas variables.
  2279.  
  2280. inic_general   PROC
  2281.                MOV   AX,(bytes_resid+15)/16
  2282.                MOV   longitud_total,AX ; memoria necesaria
  2283.                MOV   segmento_real,CS  ; anotar segmento del bloque
  2284.                MOV   offset_real,0     ; ídem con el offset
  2285.                RET
  2286. inic_general   ENDP
  2287.  
  2288. ; ------------ Comprobar que la configuración es la adecuada. Para
  2289. ;              saber si la INT 13h de este ordenador acaba llamando a
  2290. ;              la INT 40h, se desvía la INT 40h y se provoca un inocuo
  2291. ;              reset de disquetes vía INT 13h para comprobar si pasa
  2292. ;              por la INT 40h.
  2293.  
  2294. analiza_equipo PROC
  2295.                PUSH  ES
  2296.                CALL  testAT
  2297.                MOV   AX,ERR_TIPOPC
  2298.                JNC   cod_err_ok        ; no es PC/XT
  2299.                CALL  test_i40
  2300.                XOR   AX,AX
  2301. cod_err_ok:    OR    error,AX
  2302.                POP   ES
  2303.                RET
  2304. analiza_equipo ENDP
  2305.  
  2306.                ; --- Comprobar si la INT 40h está en uso
  2307.  
  2308. test_i40:      XPUSH <DS, ES>          ; *
  2309.                MOV   AX,3540h
  2310.                INT   21h
  2311.                XPUSH <ES, BX>          ; vector de INT 40h original
  2312.                LEA   DX,i40_aux
  2313.                MOV   AX,2540h
  2314.                INT   21h               ; establecer nueva INT 40h
  2315.                XOR   AX,AX
  2316.                MOV   DL,0
  2317.                INT   13h               ; reset de disco
  2318.                XPOP  <DX, DS>
  2319.                MOV   AX,2540h
  2320.                INT   21h               ; restaurar INT 40h original
  2321.                XPOP  <ES, DS>          ; *
  2322.                RET
  2323.  
  2324. i40_aux        PROC
  2325.                OR    CS:accion,I40     ; sí utilizada INT 40h
  2326.                IRET                    ; desde la INT 13h
  2327. i40_aux        ENDP
  2328.  
  2329.                ; ----- Detectar 286 ó superior.
  2330.  
  2331. testAT         PROC
  2332.                PUSHF
  2333.                POP   AX
  2334.                OR    AH,70h        ; intentar activar bit 12, 13 ó 14
  2335.                PUSH  AX            ; del registro de estado
  2336.                POPF
  2337.                PUSHF
  2338.                POP   AX
  2339.                AND   AH,0F0h
  2340.                CMP   AH,0F0h
  2341.                JE    testedAT
  2342.                STC
  2343. testedAT:      CMC                 ; CF = 0 en AT y 1 en PC/XT
  2344.                RET
  2345. testAT         ENDP
  2346.  
  2347. ; ------------ Desviar también INT 13h ya que en esta máquina el
  2348. ;              gestor de INT 13h no invoca la INT 40h.
  2349.  
  2350. set_i13        PROC
  2351.                INC   offsets_ints      ; usado un vector más
  2352.                INC   BYTE PTR tabla_vectores-1
  2353.                MOV   AX,CS
  2354.                MOV   CX,16
  2355.                MUL   CX
  2356.                ADD   AX,pbuffer
  2357.                ADC   DX,0              ; DX:AX = dirección 20 bits
  2358.                MOV   CX,DX
  2359.                PUSH  AX
  2360.                ADD   AX,511            ; buffer para el mayor sector
  2361.                ADC   DX,0
  2362.                POP   AX
  2363.                CMP   DX,CX
  2364.                JE    dma_ok
  2365.                NEG   AX
  2366.                ADD   pbuffer,AX        ; saltar hasta próxima frontera
  2367.                OR    accion,BUFFERPLUS
  2368. dma_ok:        MOV   AX,pbuffer
  2369.                ADD   AX,512
  2370.                SUB   AX,OFFSET ges_int13
  2371.                ADD   AX,15
  2372.                MOV   CL,4
  2373.                SHR   AX,CL
  2374.                ADD   longitud_total,AX ; es necesaria más memoria
  2375.                RET
  2376. set_i13        ENDP
  2377.  
  2378. ; ------------ Establecer el tipo de las unidades a nivel DOS.
  2379.  
  2380. set_dev_params PROC
  2381.                MOV   AH,30h
  2382.                INT   21h
  2383.                XCHG  AH,AL
  2384.                CMP   AX,314h
  2385.                JB    dev_set           ; DOS < 3.2 -> no soportado
  2386.                MOV   BX,1
  2387. set_otro_dev:  PUSH  BX
  2388.                MOV   AH,8
  2389.                MOV   DL,BL
  2390.                DEC   DL
  2391.                PUSH  BX
  2392.                PUSH  ES
  2393.                INT   13h               ; obtener tipo de la unidad
  2394.                POP   ES
  2395.                MOV   BH,0
  2396.                SHL   BX,1
  2397.                ADD   BX,OFFSET ptr_dev_info
  2398.                MOV   DX,[BX]           ; DS:DX -> tabla de información
  2399.                POP   BX
  2400.                AND   DX,DX
  2401.                JZ    device_set
  2402.                MOV   AX,440Dh          ; IOCTL
  2403.                MOV   CX,0840h
  2404.                INT   21h               ; establecer tipo de soporte
  2405. device_set:    POP   BX
  2406.                INC   BX
  2407.                CMP   BX,2
  2408.                JBE   set_otro_dev
  2409. dev_set:       RET
  2410. set_dev_params ENDP
  2411.  
  2412. ; ------------ Preservar vectores de interrupción previos.
  2413.  
  2414. preservar_INTs PROC
  2415.                XPUSH <ES, DI>
  2416.                LEA   DI,tabla_vectores
  2417.                MOV   CL,[DI-1]
  2418.                MOV   CH,0              ; CX vectores interceptados
  2419. otro_vector:   XPUSH <CX, DI>
  2420.                MOV   AH,35h
  2421.                MOV   AL,[DI]
  2422.                INT   21h               ; obtener vector de INT xx
  2423.                XPOP  <DI, CX>
  2424.                MOV   [DI+1],BX         ; anotar donde apunta
  2425.                MOV   [DI+3],ES
  2426.                ADD   DI,5
  2427.                LOOP  otro_vector       ; repetir con los restantes
  2428.                XPOP  <DI, ES>
  2429.                RET
  2430. preservar_INTs ENDP
  2431.  
  2432. ; ------------ desviar vectores de interrupción a las nuevas rutinas.
  2433.  
  2434. activar_INTs   PROC
  2435.                LEA   SI,offsets_ints
  2436.                MOV   CX,CS:[SI]        ; CX vectores a desviar
  2437.                ADD   SI,2
  2438. desvia_otro:   MOV   AL,CS:[SI]        ; número del vector en curso
  2439.                MOV   DX,CS:[SI+1]      ; obtener offset
  2440.                MOV   AH,25h
  2441.                INT   21h               ; desviar INT xx a DS:DX
  2442.                ADD   SI,3
  2443.                LOOP  desvia_otro
  2444.                RET
  2445. activar_INTs   ENDP
  2446.  
  2447. ; ------------ Buscar entrada no usada en la interrupción Multiplex.
  2448. ;              A la salida, CF=1 si no hay hueco (ya hay 64 programas
  2449. ;              residentes instalados con esta técnica). Si CF=0, se
  2450. ;              devuelve en AH un valor de entrada libre en la INT 2Fh.
  2451.  
  2452. mx_get_handle  PROC
  2453.                MOV   AH,0C0h
  2454. mx_busca_hndl: PUSH  AX
  2455.                MOV   AL,0
  2456.                INT   2Fh
  2457.                CMP   AL,0FFh
  2458.                POP   AX
  2459.                JNE   mx_si_hueco
  2460.                INC   AH
  2461.                JNZ   mx_busca_hndl
  2462.                STC
  2463.                RET
  2464. mx_si_hueco:   CLC
  2465.                RET
  2466. mx_get_handle  ENDP
  2467.  
  2468. ; ------------ Devolver CF=0 si 2M o 2MX están instalados o se ha
  2469. ;              cargado el código 2M en modo SuperBOOT.
  2470.  
  2471. hay2m?         PROC
  2472.                PUSH  ES
  2473.                LEA   SI,id_2m          ; identificación del programa
  2474.                MOV   CX,id_2m_tam
  2475.                MOV   AX,1492h
  2476.                MOV   ES,AX
  2477.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  2478.                CALL  mx_find_tsr       ; buscar si está en memoria
  2479.                JNC   hay2m?_ret
  2480.                LEA   SI,id_2mx         ; identificación del programa
  2481.                MOV   CX,id_2mx_tam
  2482.                CALL  mx_find_tsr
  2483.                JNC   hay2m?_ret
  2484.                INT   12h               ; tamaño memoria convencional
  2485.                CMP   AX,640
  2486.                JBE   base_sc_ok
  2487.                MOV   AX,640            ; alguien la ha manipulado
  2488. base_sc_ok:    SUB   AX,5
  2489.                MOV   BX,64
  2490.                MUL   BX                ; AX = segmento de SuperBOOT
  2491.                MOV   CX,6
  2492. scan_boot:     PUSH  CX
  2493.                MOV   ES,AX
  2494.                MOV   DI,6
  2495.                LEA   SI,id_boot
  2496.                MOV   CX,id_boot_tam
  2497.                CLD
  2498.                REP   CMPSB
  2499.                POP   CX
  2500.                JE    hay2m?_ret        ; CF = 0 -> 2M SuperBOOT
  2501.                SUB   AX,1000h
  2502.                LOOP  scan_boot         ; buscar 64K más abajo
  2503.                STC
  2504. hay2m?_ret:    POP   ES
  2505.                RET
  2506. hay2m?         ENDP
  2507.  
  2508. ; ------------ Comprobar si el programa ya reside en memoria. A la
  2509. ;              salida, CF=0 si programa ya reside, con «tsr_seg» y
  2510. ;              «tsr_off» inicializadas apuntando a la cadena de
  2511. ;              identificación de la copia residente.  Si CF=1, el
  2512. ;              programa no reside aún (AX=0) o reside pero en otra
  2513. ;              versión distinta (AX=1).
  2514.  
  2515. residente?     PROC
  2516.                XPUSH <CX, SI, DI, ES, AX>
  2517.                LEA   DI,autor_nom_ver  ; identificación del programa
  2518.                MOV   SI,DI
  2519.                MOV   AL,0
  2520.                MOV   CL,255
  2521.                CLD
  2522.                REPNE SCASB
  2523.                SUB   DI,SI
  2524.                MOV   CX,DI             ; tamaño autor+programa+versión
  2525.                MOV   AX,1492h
  2526.                MOV   ES,AX
  2527.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  2528.                CALL  mx_find_tsr       ; buscar si está en memoria
  2529.                MOV   tsr_off,DI        ; anotar la dirección programa
  2530.                MOV   tsr_seg,ES        ; por si estaba instalado
  2531.                POP   AX
  2532.                JNC   resid_ok          ; CF=0 -> programa ya residente
  2533.                POP   ES
  2534.                PUSH  ES
  2535.                LEA   DI,autor_nom_ver
  2536.                MOV   SI,DI
  2537.                MOV   AL,':'
  2538.                MOV   CL,255
  2539.                REPNE SCASB
  2540.                REPNE SCASB
  2541.                SUB   DI,SI
  2542.                MOV   CX,DI             ; tamaño autor+programa
  2543.                MOV   AX,1492h
  2544.                MOV   ES,AX
  2545.                MOV   DI,1992h          ; ES:DI protocolo de búsqueda
  2546.                CALL  mx_find_tsr       ; buscar si está en memoria
  2547.                MOV   tsr_off,DI        ; anotar dirección del programa
  2548.                MOV   tsr_seg,ES        ; por si instalada otra versión
  2549.                MOV   AX,0
  2550.                JC    resid_ok          ; CF=1, AX=0 -> no residente
  2551.                MOV   AX,1
  2552.                STC                     ; CF=1, AX=1 -> sí: otra vers.
  2553. resid_ok:      XPOP  <ES, DI, SI, CX>
  2554.                RET
  2555. residente?     ENDP
  2556.  
  2557. ; ------------ Buscar un TSR por la interrupción Multiplex. A la
  2558. ;              entrada, DS:SI cadena de identificación del programa
  2559. ;              (CX bytes) y ES:DI protocolo de búsqueda (normalmente
  2560. ;              1492h:1992h). A la salida, si el TSR ya está instalado,
  2561. ;              CF=0 y ES:DI apunta a la cadena de identificación del
  2562. ;              mismo. Si no, CF=1 y ningún registro alterado.
  2563.  
  2564. mx_find_tsr    PROC
  2565.                MOV   AH,0C0h
  2566. mx_rep_find:   XPUSH <AX, CX, SI, DS, ES, DI>
  2567.                MOV   AL,0
  2568.                PUSH  CX
  2569.                INT   2Fh
  2570.                POP   CX
  2571.                CMP   AL,0FFh
  2572.                JNE   mx_skip_hndl      ; no hay TSR ahí
  2573.                CLD
  2574.                PUSH  DI
  2575.                REP   CMPSB             ; comparar identificación
  2576.                POP   DI
  2577.                JE    mx_tsr_found      ; programa buscado hallado
  2578. mx_skip_hndl:  XPOP  <DI, ES, DS, SI, CX, AX>
  2579.                INC   AH
  2580.                JNZ   mx_rep_find
  2581.                STC
  2582.                RET
  2583. mx_tsr_found:  ADD   SP,4              ; «sacar» ES y DI de la pila
  2584.                XPOP  <DS, SI, CX, AX>
  2585.                CLC
  2586.                RET
  2587. mx_find_tsr    ENDP
  2588.  
  2589. ; ------------ Informar al usuario.
  2590.  
  2591. info           PROC
  2592.                TEST  error,0FFFFh
  2593.                JZ    info_mas
  2594.                LEA   DX,no_inst_txt
  2595.                CALL  print
  2596.                LEA   DX,mal_cpu_txt
  2597.                TEST  error,ERR_TIPOPC
  2598.                JNZ   print_err
  2599.                LEA   DX,hay2m_txt
  2600.                TEST  error,ERR_HAY2M
  2601.                JNZ   print_err
  2602.                LEA   DX,null_drv_txt
  2603.                TEST  error,ERR_MALDRV
  2604.                JNZ   print_err
  2605.                LEA   DX,err_syntax_txt
  2606.                TEST  error,ERR_SYNTAX
  2607.                JNZ   print_err
  2608.                LEA   DX,err_mx64full
  2609.                TEST  error,MX64FULL
  2610.                JZ    fin_info
  2611. print_err:     CALL  print
  2612.                RET
  2613. info_mas:      LEA   DX,instalado_txt
  2614.                CALL  print
  2615.                CALL  info_drives
  2616.                TEST  accion,BUFFERPLUS
  2617.                JZ    fin_info
  2618.                LEA   DX,dma_cross_txt
  2619.                CALL  print
  2620. fin_info:      RET
  2621. info           ENDP
  2622.  
  2623.                ; --- Informar de las unidades controladas.
  2624.  
  2625. info_drives    PROC
  2626.                MOV   AH,8
  2627.                MOV   DL,0
  2628.                INT   13h
  2629.                JC    info_null         ; no hay información sobre A:
  2630.                AND   BL,BL
  2631.                JZ    info_null
  2632.                CMP   DL,1
  2633.                JB    info_null
  2634.                PUSH  DX
  2635.                MOV   BH,0
  2636.                DEC   BX
  2637.                SHL   BX,1
  2638.                LEA   DX,a_txt          ; "A:"
  2639.                CALL  print
  2640.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2641.                CALL  print
  2642.                POP   DX
  2643.                CMP   DL,2
  2644.                JB    info_exit         ; no hay información sobre B:
  2645.                MOV   AH,8
  2646.                MOV   DL,1
  2647.                INT   13h
  2648.                JC    info_exit
  2649.                AND   BL,BL
  2650.                JZ    info_exit
  2651.                MOV   BH,0
  2652.                DEC   BX
  2653.                SHL   BX,1
  2654.                LEA   DX,b_txt          ; "B:"
  2655.                CALL  print
  2656.                MOV   DX,[BX+OFFSET ptr_txt_tipos]  ; su tipo
  2657.                CALL  print
  2658. info_exit:     LEA   DX,i40_txt
  2659.                TEST  accion,I40
  2660.                JNZ   imodo_ok
  2661.                LEA   DX,i13_txt
  2662. imodo_ok:      CALL  print             ; modo de instalación
  2663.                RET
  2664. info_null:     LEA   DX,null_drv_txt   ; sin indicar tipo de unidades
  2665.                CALL  print
  2666.                RET
  2667. info_drives    ENDP
  2668.  
  2669. ; ------------ Calcular la constante de retardo básica para perder
  2670. ;              exactamente 54,925 ms. Con una regla de 3 se podrá
  2671. ;              después aplicar para hacer retardos de milisegundos.
  2672.  
  2673. cte_tiempos    PROC
  2674.                XPUSH <DS, ES, BX, CX, DX>
  2675.                MOV   AX,3508h
  2676.                INT   21h
  2677.                XPUSH <ES, BX>          ; preservar vector de INT 8
  2678.                PUSH  DS
  2679.                MOV   AX,40h
  2680.                MOV   DS,AX
  2681.                MOV   AL,DS:[6Ch]
  2682. espera_i8:     CMP   AL,DS:[6Ch]
  2683.                JE    espera_i8         ; esperar INT 8 ... para que no
  2684.                POP   DS
  2685.                LEA   DX,i8_crono       ; venga otra en un buen rato...
  2686.                MOV   AX,2508h
  2687.                INT   21h               ; nueva rutina de INT 8
  2688.                IN    AL,21h
  2689.                PUSH  AX                ; preservar estado de IRQ's
  2690.                MOV   AL,11111110b
  2691.                OUT   21h,AL            ; permitir sólo IRQ0
  2692.                MOV   AH,0              ; fase
  2693.                MOV   CX,0              ; contador
  2694.                MOV   BX,CX             ; seguiría a 0 si fallara
  2695.                EVEN                    ; forzar alineamiento
  2696. cuenta_iter:   DEC   CX                ; <─┐ bucle básico de retardo
  2697.                JMP   SHORT $+2         ;   │
  2698.                JNZ   cuenta_iter       ; <─┘ lo interrumpirá INT 8
  2699.                POP   AX                ; anterior estado de IRQ's
  2700.                OUT   21h,AL
  2701.                XPOP  <DX, DS>
  2702.                PUSH  BX                ; valor real contado
  2703.                MOV   AX,2508h          ; restaurar vector de INT 8
  2704.                INT   21h
  2705.                POP   AX                ; (65536-AX) vueltas en 54,9 ms
  2706.                NEG   AX                ; constante de retardo básica
  2707.                XPOP  <DX, CX, BX, ES, DS>
  2708.                RET
  2709. i8_crono:      INC   AH                ; nueva INT 8 que interrumpe
  2710.                CMP   AH,1              ; el bucle de retardo
  2711.                JE    fase1
  2712.                CMP   AH,2
  2713.                JE    fase2
  2714. i8_exit:       MOV   AL,20h
  2715.                OUT   20h,AL
  2716.                IRET
  2717. fase1:         MOV   CX,0              ; sincronizar con el reloj
  2718.                JMP   i8_exit
  2719. fase2:         MOV   BX,CX             ; anotar constante de retardo
  2720.                MOV   CX,1              ; forzar fin del bucle
  2721.                JMP   i8_exit
  2722. cte_tiempos    ENDP
  2723.  
  2724. ; ------------ Inicializar variables en el área de datos de la BIOS.
  2725.  
  2726. init_vars      PROC
  2727.                PUSH  DS
  2728.                MOV   AX,40h
  2729.                MOV   DS,AX
  2730.                AND   BYTE PTR DS:[3Eh],01110000b
  2731.                MOV   BYTE PTR DS:[8Bh],00000000b
  2732.                MOV   DX,3F7h
  2733.                MOV   AL,0
  2734.                OUT   DX,AL
  2735.                MOV   BYTE PTR DS:[8Fh],01110111b
  2736.                MOV   BYTE PTR DS:[90h],0
  2737.                MOV   BYTE PTR DS:[91h],0
  2738.                POP   DS
  2739.                RET
  2740. init_vars      ENDP
  2741.  
  2742. ; ------------ Inicializar variable idioma_sp según idioma del país.
  2743.  
  2744. habla_hispana? PROC
  2745.                XPUSH <AX, BX, CX, DX, BP>
  2746.                MOV   AH,30h
  2747.                INT   21h
  2748.                XCHG  AH,AL             ; AX = versión del DOS
  2749.                MOV   BP,AX
  2750.                MOV   idioma_sp,OFF     ; supuesto de habla no hispana
  2751.                CMP   BP,200h
  2752.                JB    habla_ok
  2753.                LEA   DX,buffer_aux
  2754.                MOV   AX,3800h
  2755.                INT   21h               ; obtener información del pais
  2756.                CMP   BP,20Bh
  2757.                JE    habla_ax          ; DOS 2.11: AX cód. telefónico
  2758.                CMP   BP,300h
  2759.                JB    habla_ok          ; 2.x excepto 2.11: mala suerte
  2760.                MOV   AX,BX
  2761. habla_ax:      LEA   BX,paises_sp-2
  2762.                MOV   CX,numpaises_sp
  2763. habla_sp?:     ADD   BX,2
  2764.                CMP   AX,[BX]
  2765.                JE    habla_hispana
  2766.                LOOP  habla_sp?
  2767. habla_ok:      MOV   AL,param_i
  2768.                XOR   idioma_sp,AL      ; considerar parámetro /I
  2769.                XPOP  <BP, DX, CX, BX, AX>
  2770.                RET
  2771. habla_hispana: MOV   idioma_sp,ON      ; país de habla hispana
  2772.                MOV   AL,param_i
  2773.                XOR   idioma_sp,AL      ; considerar parámetro /I
  2774.                XPOP  <BP, DX, CX, BX, AX>
  2775.                RET
  2776. habla_hispana? ENDP
  2777.  
  2778. ; ------------ Imprimir cadena en DS:DX delimitada por un 0 ó un 255.
  2779. ;              Si hay que imprimir en inglés se toma la cadena que va
  2780. ;              después si ésta acaba en 255 (si acaba en 0, no hay
  2781. ;              distinción entre mensaje castellano e inglés).
  2782.  
  2783. print          PROC
  2784.                XPUSH <AX, BX, CX, DX>
  2785. pr_decidir:    CMP   idioma_sp,OFF
  2786.                JE    usar_uk
  2787.                CMP   idioma_sp,ON
  2788.                JE    usar_sp
  2789.                PUSH  DX
  2790.                CALL  habla_hispana?         ; determinar lengua
  2791.                POP   DX
  2792.                JMP   pr_decidir
  2793. usar_uk:       MOV   BX,DX
  2794.                DEC   BX
  2795. usar_uk?:      INC   BX
  2796.                CMP   BYTE PTR [BX],0
  2797.                JE    usar_sp                ; acaba en 0: no traducir
  2798.                CMP   BYTE PTR [BX],255
  2799.                JNE   usar_uk?
  2800.                LEA   DX,[BX+1]              ; acaba en 255: traducir
  2801. usar_sp:       MOV   BX,DX
  2802.                DEC   BX
  2803. print_cad:     INC   BX
  2804.                CMP   BYTE PTR [BX],0
  2805.                JE    prlong_ok
  2806.                CMP   BYTE PTR [BX],255
  2807.                JNE   print_cad              ; calcular longitud
  2808. prlong_ok:     MOV   CX,BX
  2809.                SUB   CX,DX
  2810.                MOV   AH,40h
  2811.                MOV   BX,1
  2812.                INT   21h
  2813.                XPOP  <DX, CX, BX, AX>
  2814.                RET
  2815. print          ENDP
  2816.  
  2817. ; ************ Datos no residentes para la instalación
  2818.  
  2819. ON             EQU   1                 ; constantes booleanas
  2820. OFF            EQU   0
  2821.  
  2822. param_i        DB    OFF               ; a ON si indicado parámetro /I
  2823. param_hlp      DB    OFF               ; a ON si se solicita ayuda
  2824.  
  2825. tsr_dir        LABEL DWORD     ; dirección de la copia residente
  2826. tsr_off        DW    0
  2827. tsr_seg        DW    0
  2828.  
  2829. tipos_drv      DB    -1                ; tipo de A:
  2830.                DB    -1                ; y de B:
  2831.  
  2832. id_2m          DB    "CiriSOFT:2M:"
  2833. id_2m_tam      EQU   $-OFFSET id_2m
  2834. id_2mx         DB    "CiriSOFT:2MX:"
  2835. id_2mx_tam     EQU   $-OFFSET id_2mx
  2836. id_boot        DB    "2M-STV"
  2837. id_boot_tam    EQU   $-OFFSET id_boot
  2838.  
  2839. ERR_TIPOPC     EQU   1                 ; códigos de error
  2840. ERR_HAY2M      EQU   2
  2841. ERR_MALDRV     EQU   4
  2842. ERR_SYNTAX     EQU   8
  2843. MX64FULL       EQU  16
  2844.  
  2845. I40            EQU   1                 ; códigos de acción
  2846. BUFFERPLUS     EQU   2
  2847.  
  2848. offsets_ints   DW    3         ; número de vectores interceptados
  2849.                DB    15h       ; tabla de offsets de los vectores
  2850.                DW    ges_int15 ; de interrupción interceptados
  2851.                DB    2Fh
  2852.                DW    ges_int2F
  2853.                DB    40h
  2854.                DW    ges_int40
  2855.                DB    13h       ; INT 13h podría usarse
  2856.                DW    ges_int13
  2857.  
  2858. ptr_dev_info   DW    0, i360, i1200, i720, i1440, i2880
  2859.  
  2860. i360           DB    4, 0              ; sectores iguales / tipo 360K
  2861.                DW    0, 40             ; no detecta cambio / nº pistas
  2862.                DB    1                 ; tipo de soporte
  2863.                DW    512               ; BPB: bytes por sector
  2864.                DB    2                 ; BPB: sectores por cluster
  2865.                DW    1                 ; BPB: sectores reservados
  2866.                DB    2                 ; BPB: número de FATs
  2867.                DW    112               ; BPB: entradas en el raíz
  2868.                DW    720               ; BPB: nº total de sectores
  2869.                DB    0FDh              ; BPB: descriptor de medio
  2870.                DW    2                 ; BPB: sectores por FAT
  2871.                DW    9, 2              ; BPB: sectores pista / cabezas
  2872.                DB    14 DUP (0)        ; BPB: restantes campos
  2873. i1200          DB    4, 1              ; sectores iguales / tipo 1.2M
  2874.                DW    2, 80             ; detecta cambio / nº pistas
  2875.                DB    0                 ; tipo de soporte
  2876.                DW    512               ; BPB: bytes por sector
  2877.                DB    1                 ; BPB: sectores por cluster
  2878.                DW    1                 ; BPB: sectores reservados
  2879.                DB    2                 ; BPB: número de FATs
  2880.                DW    224               ; BPB: entradas en el raíz
  2881.                DW    2400              ; BPB: nº total de sectores
  2882.                DB    0F9h              ; BPB: descriptor de medio
  2883.                DW    7                 ; BPB: sectores por FAT
  2884.                DW    15, 2             ; BPB: sectores pista / cabezas
  2885.                DB    14 DUP (0)        ; BPB: restantes campos
  2886. i720           DB    4, 2              ; sectores iguales / tipo 720K
  2887.                DW    0, 80             ; no detecta cambio / nº pistas
  2888.                DB    0                 ; tipo de soporte
  2889.                DW    512               ; BPB: bytes por sector
  2890.                DB    2                 ; BPB: sectores por cluster
  2891.                DW    1                 ; BPB: sectores reservados
  2892.                DB    2                 ; BPB: número de FATs
  2893.                DW    112               ; BPB: entradas en el raíz
  2894.                DW    1440              ; BPB: nº total de sectores
  2895.                DB    0F9h              ; BPB: descriptor de medio
  2896.                DW    3                 ; BPB: sectores por FAT
  2897.                DW    9, 2              ; BPB: sectores pista / cabezas
  2898.                DB    14 DUP (0)        ; BPB: restantes campos
  2899. i1440          DB    4, 7              ; sectores iguales / tipo 1.44M
  2900.                DW    2, 80             ; detecta cambio / nº pistas
  2901.                DB    0                 ; tipo de soporte
  2902.                DW    512               ; BPB: bytes por sector
  2903.                DB    1                 ; BPB: sectores por cluster
  2904.                DW    1                 ; BPB: sectores reservados
  2905.                DB    2                 ; BPB: número de FATs
  2906.                DW    224               ; BPB: entradas en el raíz
  2907.                DW    2880              ; BPB: nº total de sectores
  2908.                DB    0F0h              ; BPB: descriptor de medio
  2909.                DW    9                 ; BPB: sectores por FAT
  2910.                DW    18, 2             ; BPB: sectores pista / cabezas
  2911.                DB    14 DUP (0)        ; BPB: restantes campos
  2912. i2880          DB    4, 9              ; sectores iguales / tipo 2.88M
  2913.                DW    2, 80             ; detecta cambio / nº pistas
  2914.                DB    0                 ; tipo de soporte
  2915.                DW    512               ; BPB: bytes por sector
  2916.                DB    2                 ; BPB: sectores por cluster
  2917.                DW    1                 ; BPB: sectores reservados
  2918.                DB    2                 ; BPB: número de FATs
  2919.                DW    224               ; BPB: entradas en el raíz
  2920.                DW    5760              ; BPB: nº total de sectores
  2921.                DB    0F0h              ; BPB: descriptor de medio
  2922.                DW    9                 ; BPB: sectores por FAT
  2923.                DW    36, 2             ; BPB: sectores pista / cabezas
  2924.                DB    14 DUP (0)        ; BPB: restantes campos
  2925.  
  2926. accion         DW    0
  2927. error          DW    0
  2928. idioma_sp      DB    5Ah       ; ni en ON ni en OFF al principio
  2929.  
  2930.                ; --- Código telefónico de países de
  2931.                ;     habla hispana (mucha o poca).
  2932.  
  2933. paises_sp      DW    54                ; Argentina
  2934.                DW    591               ; Bolivia
  2935.                DW    57                ; Colombia
  2936.                DW    506               ; Costa Rica
  2937.                DW    56                ; Chile
  2938.                DW    593               ; Ecuador
  2939.                DW    503               ; El Salvador
  2940.                DW    34                ; España
  2941.                DW    63                ; Filipinas
  2942.                DW    502               ; Guatemala
  2943.                DW    504               ; Honduras
  2944.                DW    212               ; Marruecos
  2945.                DW    52                ; México
  2946.                DW    505               ; Nicaragua
  2947.                DW    507               ; Panamá
  2948.                DW    595               ; Paraguay
  2949.                DW    51                ; Perú
  2950.                DW    80                ; Puerto Rico
  2951.                DW    508               ; República Dominicana
  2952.                DW    598               ; Uruguay
  2953.                DW    58                ; Venezuela
  2954.                DW    3                 ; genérico latinoamérica
  2955. numpaises_sp   EQU   ($-OFFSET paises_sp)/2
  2956.  
  2957. ; ------------ Texto.
  2958.  
  2959. info_adj_txt   DB    13,10,"2M-XBIOS 1.2 ya instalado, base de tiempos ajustada.",13,10,255
  2960.                DB    13,10,"2M-XBIOS 1.2 already installed, delay constant adjusted.",13,10,255
  2961.  
  2962. instalado_txt  DB    13,10,"2M-XBIOS 1.2 instalado en ",255
  2963.                DB    13,10,"2M-XBIOS 1.2 installed on ",0
  2964.  
  2965. a_txt          DB    "A:",0
  2966. b_txt          DB    " y B:",255," and B:",0
  2967. ptr_txt_tipos  DW    d360, d1200, d720, d1440, d2880
  2968. d360           DB    "360K",0
  2969. d1200          DB    "1.2M",0
  2970. d720           DB    "720K",0
  2971. d1440          DB    "1.44M",0
  2972. d2880          DB    "2.88M",0
  2973. i40_txt        DB    "  [INT 40h]",13,10,0
  2974. i13_txt        DB    "  [INT 13h]",13,10,0
  2975.  
  2976. no_inst_txt    DB    13,10,"2M-XBIOS 1.2 *NO* instalado.",13,10,255
  2977.                DB    13,10,"2M-XBIOS 1.2 *NOT* installed.",13,10,0
  2978.  
  2979. mal_cpu_txt    DB    "  + Error: necesario equipo PC/XT. Utilice 2M-ABIOS en este equipo.",13,10,255
  2980.                DB    "  + Error: needs a PC/XT system. Try 2M-ABIOS on this system.",13,10,0
  2981.  
  2982. hay2m_txt      DB    "  + Error: 2M-XBIOS debe instalarse *ANTES* de 2MX (y nunca en SuperBOOT).",13,10,255
  2983.                DB    "  + Error: 2M-XBIOS must be installed *BEFORE* 2MX (and never in SuperBOOT).",13,10,0
  2984.  
  2985. null_drv_txt   DB    "  + Utilice los parámetros para indicar expresamente el tipo de las unidades.",13,10,255
  2986.                DB    "  + Please use the switches to set the correct diskette drives type.",13,10,0
  2987.  
  2988. err_syntax_txt DB    "  + Error de sintaxis: ejecútelo desde el símbolo DOS para obtener ayuda.",13,10,255
  2989.                DB    "  + Syntax error: execute from DOS command line to obtain help.",13,10,0
  2990.  
  2991. err_mx64full   DB    "  + Error: Ya hay 64 programas residentes con la misma técnica.",13,10,7,255
  2992.                DB    "  + Error: There are already 64 TSR's with the same technique.",13,10,7,0
  2993.  
  2994. dma_cross_txt  DB    "    - Nota: El buffer de E/S cruzaba una frontera de DMA y fue ampliado.",13,10
  2995.                DB    "            Cambie la ubicación en memoria si desea ahorrar unos bytes.",13,10,255
  2996.                DB    "    - Note: I/O buffer has been extended because it crosses a DMA boundary.",13,10
  2997.                DB    "            Modify the memory location of 2M-XBIOS to save a little memory.",13,10,0
  2998.  
  2999. info_txt       LABEL BYTE
  3000.                DB    13,10
  3001.                DB    "           2M-XBIOS 1.2  -  (c) Mayo 1994 Ciriaco García de Celis.",13,10
  3002.                DB    " C/Renedo, 2, 4-C; 47005 Valladolid (España) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3003.                DB    "               Sintaxis:  DEVICE=2M-XBIOS.EXE [A:tipo [B:tipo]]",13,10,10
  3004.                DB    "    La mayoría de PC/XT tiene una BIOS antigua sin soporte de alta densidad",13,10
  3005.                DB    "  aunque admiten una controladora de AT de alta densidad. Para trabajar con",13,10
  3006.                DB    "  unidades de alta densidad necesitan 2M-XBIOS.  Además, 2MX suele requerir",13,10
  3007.                DB    "  que esté instalado 2M-XBIOS,  que debería ser cargado antes que cualquier",13,10
  3008.                DB    "  otro software de disco. Este programa es sólo para máquinas PC/XT.",13,10,10
  3009.                DB    "    2M-XBIOS  actualiza el soporte de disco flexible a la última tecnología",13,10
  3010.                DB    "  de las BIOS AMI de 1993. Si con 2M-XBIOS instalado 2MX no opera de manera",13,10
  3011.                DB    "  totalmente correcta y en su máquina no está instalado algún otro software",13,10
  3012.                DB    "  de disco incompatible con 2MX entonces su ordenador no es 100% compatible",13,10
  3013.                DB    "  hardware con el estándar;  esto es particularmente cierto si con 2M-XBIOS",13,10
  3014.                DB    "  instalado no se reconocen siquiera los discos estándar del DOS.",13,10,10
  3015.                DB    "    Este programa ocupa 3.4-4.2 Kb de RAM, y contiene una emulación al 100%",13,10
  3016.                DB    "  del eficaz código de control de disco de las BIOS AMI,  relevando así por",13,10
  3017.                DB    "  completo de esta tarea a la BIOS del sistema. Generalmente será necesario",13,10
  3018.                DB    "  indicar el tipo (0:no hay, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M). AMI",13,10
  3019.                DB    "  es marca registrada de American Megatrends Inc.",13,10
  3020.                DB    255
  3021.                DB    13,10,10
  3022.                DB    "           2M-XBIOS 1.2  -  (c) Mayo 1994 Ciriaco García de Celis.",13,10
  3023.                DB    "  C/Renedo, 2, 4-C; 47005 Valladolid (Spain) - ciri@gui.uva.es - 2:341/21.8",13,10,10
  3024.                DB    "               Syntax:  DEVICE=2M-XBIOS.EXE [A:type [B:type]]",13,10,10
  3025.                DB    "    Most  PC/XT  systems have an old BIOS with no high density support, but",13,10
  3026.                DB    "  they can be equiped with an AT high density disk controller. To work with",13,10
  3027.                DB    "  high density drives they need 2M-XBIOS.  Also,  2MX  usually requires the",13,10
  3028.                DB    "  previous installation of 2M-XBIOS:  you  must install it before any other",13,10
  3029.                DB    "  disk TSR software. This program is only for use on PC/XT systems.",13,10,10
  3030.                DB    "    2M-XBIOS upgrades floppy-disk support to last AMI BIOS 1993 technology.",13,10
  3031.                DB    "  If 2M-XBIOS is installed, and 2MX continues not working full correctly on",13,10
  3032.                DB    "  your computer, and is not installed in the system any other disk software",13,10
  3033.                DB    "  incompatible with 2MX, this probably means that your computer is not 100%",13,10
  3034.                DB    "  hardware compatible with the standard XT;  this is specially true if only",13,10
  3035.                DB    "  2M-XBIOS is installed and DOS standard diskettes don't work.",13,10,10
  3036.                DB    "    This program takes 3.4-4.2 Kb of RAM,  and provides a full emulation of",13,10
  3037.                DB    "  the effective disk control management of AMI BIOS,  absolutely overriding",13,10
  3038.                DB    "  your native BIOS in this job.  Usually, you will need to select the drive",13,10
  3039.                DB    "  type (0:not present, 1:360K, 2:1.2M, 3:720K, 4:1.44M, 5:2.88M).  AMI is a",13,10
  3040.                DB    "  registered trademark of American Megatrends Inc.",13,10
  3041.                DB    0
  3042.  
  3043. buffer_aux     DB    64 DUP (0)   ; buffer para alguna función del DOS
  3044.  
  3045. _PRINCIPAL     ENDS
  3046.  
  3047. _PILA          SEGMENT STACK 'STACK'
  3048.                DB    1024 DUP (?)      ; 1 Kb de pila es suficiente
  3049. _PILA          ENDS
  3050.  
  3051.                END   inicio
  3052.